Why cant I use an IEnumerable with params? Will this ever be fixed? I really wish they would rewrite the old libraries to use generics...


Solution 1:

Why cant I use an IEnumerable with params?

The question presupposes that the design team must provide a reason to not add a feature to the language. This presupposition is false.

Rather, in order for a feature to be used by you it needs to be thought of, designed, specified, implemented, tested, documented and shipped. All of these have large costs.

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: As of this writing -- early 2015 -- has now been specified, but implementation, testing, documentation and shipping were cut for C# 6.0 in the latter part of 2014. See Lucian's announcement here: http://roslyn.codeplex.com/discussions/568820.

Since it has still not been implemented, tested, documented and shipped, there is still no such feature. Hopefully this will make it into a hypothetical future version of C#.


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.

Solution 2:

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.

Note that when calling the above code, you'll want to explicitly specify the type argument, to avoid the compiler preferring the params example. So for example:

List<string> x = new List<string>();
Foo<string>(x);