Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there not a constructor for List<T> that takes a params argument?

I know I can use a collection initializer to initialize a list:

var list = new List<string>
{
    "test string 1",
    "test string 2"
};

If I recall, this internally calls Add for each item.

Why is there not a constructor for List<T> that takes a params T[] items?

var list = new List<string>("test string 1", "test string 2");
like image 589
xofz Avatar asked Nov 08 '13 23:11

xofz


3 Answers

The real reason is that the designers simply didn't feel that the benefit of this little bit of syntactic sugar was worth the effort of implementing or that it might cause some confusion.

There is a slight issue if you want create a List<int>. What should this mean?

var list = new List<int>(10);

Is that a new list with capacity 10, or a new list containing a single element, 10?

Spoiler, if you're not sure how the compiler will interpret it:

It will be treated as a capacity. If T is anything other than int, it will be treated as a single element. It would also be treated as a single item if you specify the parameter name—List<int>(items:10)

In any case, there's no reason you couldn't just write:

var list = new List<string>(new[] { "test string 1", "test string 2" });

This is exactly what the compiler would do if there had been a constructor that provided a params argument, and this is indeed slightly more efficient than the collection initializer. Having to type a few extra characters to accomplish this really isn't that big of a deal in the grand scheme of things.

like image 75
p.s.w.g Avatar answered Oct 14 '22 00:10

p.s.w.g


... because there isn't a compelling case to create one? In particular, there is no way of knowing that params was used as params, rather than just by passing a string[] in, so it wouldn't be able to trust that array as the backing array - so it would be an additional and unnecessary allocation of a vector. And the collection initializer syntax works pretty nicely. If you want it allocated at the correct size, you can always use:

var list = new List<string>(2)
{
    "test string 1",
    "test string 2"
};

although frankly, the number of times where this would be important is really small.

Actually, I spend a lot of time removing params usage. On a busy site, it is measurably painful (when used in a hot code path).

like image 22
Marc Gravell Avatar answered Oct 14 '22 00:10

Marc Gravell


Because nobody implemented it.

Furthermore, it's unnecessary because of collection initializer syntax, which is roughly equivalent (see @p.s.w.g.'s answer)

But! Wait... I'm feeling so generous, so consider this a gift from me to you:

public class SpecialListJustForYou<T> : List<T>
{
    public SpecialListJustForYou(int capacity):base(capacity){}
    public SpecialListJustForYou(IEnumerable<T> collection):base(collection){}
    public SpecialListJustForYou():base(){}

    // and here's the magic!
    public SpecialListJustForYou(params T[] items) : base(items == null ? Enumerable.Empty<T>() : items.AsEnumerable()){}
}
like image 40
smartcaveman Avatar answered Oct 13 '22 23:10

smartcaveman