Ответ 1
Каждый тип, который имеет метод Add и реализует IEnumerable, может быть инициализирован таким образом. Компилятор просто компилирует ваш код так, как если бы вы использовали этот метод Add.
посмотрите здесь
Я могу инициализировать List<int> like new List<int>{1,2,3,4,5};
Однако List<T>
не имеет конструктора, который принимает единственный параметр.
Поэтому я попытался запустить это через отладчик и, похоже, вызывает метод Add.
Итак, как компилятор знает, какой метод вызывать для добавления каждого отдельного элемента.
Это может быть глупый вопрос, но я немного смущен.
Спасибо
Каждый тип, который имеет метод Add и реализует IEnumerable, может быть инициализирован таким образом. Компилятор просто компилирует ваш код так, как если бы вы использовали этот метод Add.
посмотрите здесь
Это инициализатор коллекции, функция языка С# 3.0. Для этого требуется:
IEnumerable
(хотя это никогда не используется для инициализации)Add
Он просто вызывает метод Add
для каждого термина.
Вы также можете использовать кортежи, если Add
принимает несколько значений, например словари. Каждый член тогда {key,value}
:
new Dictionary<int,string> {{1,"abc"},{2,"def"}};
Пример использования этого для типа на заказ:
class Program
{
static void Main()
{
new Foo { 1, "abc", { 2, "def" } };
}
}
class Foo : IEnumerable
{
public void Add(int a) { }
public void Add(string b) { }
public void Add(int a, string b) { }
// must implement this!! (but never called)
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
}
Посмотрите на этот метод.
public void CreateList()
{
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
}
После компиляции это выглядит как MSIL.
.method public hidebysig instance void CreateList() cil managed
{
// Code size 50 (0x32)
.maxstack 2
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> list,
[1] class [mscorlib]System.Collections.Generic.List`1<int32> '<>g__initLocal0')
IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: ldc.i4.1
IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_000e: nop
IL_000f: ldloc.1
IL_0010: ldc.i4.2
IL_0011: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_0016: nop
IL_0017: ldloc.1
IL_0018: ldc.i4.3
IL_0019: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_001e: nop
IL_001f: ldloc.1
IL_0020: ldc.i4.4
IL_0021: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_0026: nop
IL_0027: ldloc.1
IL_0028: ldc.i4.5
IL_0029: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_002e: nop
IL_002f: ldloc.1
IL_0030: stloc.0
IL_0031: ret
} // end of method Program::CreateList
Как вы можете заметить, это просто синтаксический сахар, и компилятор заменяет инициализацию последовательными вызовами Add().
new List{ 1, 2, 3, 4, 5 }
- это просто синтаксический "сахар". Под обложками он просто вызывает метод Add
для каждого элемента.
Поскольку new List<int>{1,2,3,4,5}
- инициализация массива, я предпочитаю думать, что это работает изнутри по волшебству, так как я не могу повлиять на то, как это происходит. Подумав об этом, он, вероятно, определяет метод по умолчанию для добавления элементов в коллекцию в метаданных, где []
выполняется по индексу, а те, которые реализуют IList
, выполняются методом Add
.