views:

407

answers:

4

Why cant I use an IEnumerable with params? Will this change in the future?

A: 

If it were 'fixed' they would have to call it something other than IEnumerable. You can't change an interface unless you have the option of recompiling everthing that uses it.

John Knoeller
+1  A: 

The params parameters are sent as an array, and an IEnumerable<T> doesn't provide the random access that is required to act as an array.

You have to create the array from the IEnumerable when you call the method:

TheMethod(theIEnumerable.ToArray());
Guffa
+2  A: 

Ah, I think I may now have understood what you mean. I think you want to be able to declare a method like this:

public void Foo<T>(params IEnumerable<T> items)
{
}

And then be able to call it with a "normal" argument like this:

IEnumerable<string> existingEnumerable = ...;
Foo(existingEnumerable);

or with multiple parameters like this:

Foo("first", "second", "third");

Is that what you're after? (Noting that you'd want the first form to use T=string, rather than T=IEnumerable<string> with a single element...)

If so, I agree it could be useful - but it's easy enough to have:

public void Foo<T>(params T[] items)
{
    Foo((IEnumerable<T>) items);
}

public void Foo<T>(IEnumerable<T> items)
{
}

I don't find I do this often enough to make the above a particularly ugly workaround.

Jon Skeet
+13  A: 

Why cant I use an IEnumerable with params?

In order for a feature to be used by you it needs to be thought of, designed, specified, implemented, tested, documented and shipped.

The "params enumerable" feature has been thought of and designed. It has never been specified, implemented, tested, documented or shipped.

Therefore, you cannot use the feature.

UPDATE: I should clarify what I mean by "the feature" since it is possible we all have different ideas in our heads what "the feature" is. The feature I'm talking about is to allow you to say something like

void Frob(params IEnumerable<int> x)
{
    foreach(int y in x) ...
}

and then the call site can either be in the "normal form" of passing a sequence of integers, or the "expanded form" of Frob(10, 20, 30). If in the expanded form, the compiler generates the call as though you'd said Frob(new int[] { 10, 20, 30}), the same as it does for param arrays. The point of the feature is that it is often the case that the method never uses random access to the array, and therefore, we could weaken the requirement that the params be an array. The params could just be a sequence instead.

You can do this today by making an overload:

void Frob(params int[] x) { Frob((IEnumerable<int>)x); }

void Frob(IEnumerable<int> x)
{
    foreach(int y in x) ...
}

which is a bit of a pain. We could simply allow you to use IEnumerable as the type of the params argument and be done with it.

Will this ever be fixed?

I hope so. This feature has been on the list for a long time. It would make a lot of functions work much more nicely with LINQ.

Frob(from c in customers select c.Age);

without having to write two different versions of Frob.

However, it is a mere "small convenience" feature; it doesn't actually add a whole lot of new power to the language. That's why its never made it high enough on the priority list to make it to the "specification is written" stage.

I really wish they would rewrite the old libraries to use generics.

Comment noted.

Eric Lippert
Implementing this feature would basically mean an implicit call to ToArray, right?
Guffa
@Guffa, I'm not following your train of thought. I think the answer to your question is "no" but I'm not sure what question you're asking.
Eric Lippert
@Eric: The method that takes the params needs a collection with random access (not the forward-only that the IEnumerable offers), so the IEnumerable needs to be realised into a collection that has all the items all the time. The easiest way to implement this would be to simply call ToArray on the IEnumerable (or something to the same effect).
Guffa
Why does the callee need that, necessarily? The vast majority of methods that take params arrays that I've ever written just stuffed that thing into a foreach.
Eric Lippert