Does using the braced initializer on collection ty

2020-08-10 07:48发布

问题:

Does using the braced initializer on a collection type set it's capacity or do you still need to specify it?

That is, does:

var list = new List<string>(){ "One", "Two" };

result in the same as this:

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

回答1:

Object initializer simply calls Add for each item.

var list = new List<string>{ "One", "Two", "Three" };

As you can see, in this case parameterless constructor is called:

L_0000: nop 
L_0001: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
L_0006: stloc.1 
L_0007: ldloc.1 
L_0008: ldstr "One"
L_000d: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
L_0012: nop 
L_0013: ldloc.1 
L_0014: ldstr "Two"
L_0019: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
L_001e: nop 
L_001f: ldloc.1 
L_0020: ldstr "Three"
L_0025: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
L_002a: nop 
L_002b: ldloc.1 

So, you should set capacity manually:

var list = new List<string>(5){ "One", "Two", "Three" };

Compiles into:

L_0000: nop 
L_0001: ldc.i4.5 
L_0002: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor(int32)
// rest is same

So, algorithm is pretty obvious - it calls constructor which you specified (parameterless by default) and then calls Add for each item.

NOTE: I know, that default capacity is 4 for List<T> and I verified what happens if we pass more than 4 items in initializer (e.g. maybe compiler determines which constructor to call depending on items count) but result is same - parameterless constructor is called by default.

I think purpose of collection initializers is creating small collections (1 - 8 items), thus there will be a little performance impact (only one resize if you will pass 8 items into initializer). Nobody expects you will use in-place initialization with 100 items. And if you are going to do that, you should use appropriate constructor of collection.



回答2:

The collection initializer uses the available Add methods to add the items to the collection. Therefore the behaviour would be the same as using an empty constructor with calling the Add method.

Actually, the compiler will change your object initializer syntax to calls to the Add method. So, whether you use the object initializer is irrelevant. What matters is whether you decide to use the constructor overload and the amount of items you actually add.



回答3:

After List is initialised with the no-argument constructor, the internal array is set to an array of length 0.

When Add(), Insert() or InsertRange() are called the capacity of the list is recalculated:

  • If there are no other elements in the list, the capacity is set to 4 (the default capacity).
  • If there ARE other elements, the capacity is set to twice the number of elements.

If you specify the capacity, the internal array is created at that size.

References: DotNet Source: RefSrc\Source.NET 4.5\4.5.50709.0\net\ndp\clr\src\BCL\System\Collections\Generic\List.cs\597531\List.cs



回答4:

According to the documentation and considering that afer object initializer a count is 2, it will eventually set capacity too.

Capacity is always greater than or equal to Count