2009-06-18 4 views
7

При использовании нового синтаксиса инициализации коллекции C#:ли C# Коллекции Инициализации Синтаксис Избегайте умолчанию Инициализации Накладные

string[] sarray = new[] { "A", "B", "C", "D" }; 

делает компилятор избегает инициализации каждого слота массива значения по умолчанию, или это эквивалентно:

string[] sarray = new string[4]; // all slots initialized to null 
sarray[0] = "A"; 
sarray[1] = "B"; 
sarray[2] = "C"; 
sarray[3] = "D"; 

ответ

13

Компилятор все еще использует команду IL-newarr, поэтому среда CLR будет инициализировать массив.

Инициализация коллекции только компилятор магии - CLR ничего не знает об этом, поэтому он все равно предположит, что он должен сделать разминирование.

Однако это должно быть действительно, очень быстро - это просто очистка памяти. Я сомневаюсь, что это значительные накладные расходы во многих ситуациях.

+0

Интересно. Я задаюсь вопросом, является ли этот метод «уничтожения памяти» инициализацией массива одной из причин, почему структуры не поддерживают явные конструкторы по умолчанию или инициализаторы элементов. Это усложнит инициализацию массива. – LBushkin

+1

Да, это очень много. На самом деле, структуры в IL * do * поддерживают безпараметрические конструкторы, но они будут вызываться только в определенных ситуациях. –

+0

См. Http://msmvps.com/blogs/jon_skeet/archive/2008/12/10/value-types-and-parameterless-constructors.aspx для получения дополнительной информации. –

10

Быстрый тест:

 string[] arr1 = 
     { 
      "A","B","C","D" 
     }; 
     arr1.GetHashCode(); 

     string[] arr2 = new string[4]; 
     arr2[0] = "A"; 
     arr2[1] = "B"; 
     arr2[2] = "C"; 
     arr2[3] = "D"; 

     arr2.GetHashCode(); 

результатов этого IL (обратите внимание, что они оба идентичны)

IL_0002: newarr  [mscorlib]System.String 
    IL_0007: stloc.2 
    IL_0008: ldloc.2 
    IL_0009: ldc.i4.0 
    IL_000a: ldstr  "A" 
    IL_000f: stelem.ref 
    IL_0010: ldloc.2 
    IL_0011: ldc.i4.1 
    IL_0012: ldstr  "B" 
    IL_0017: stelem.ref 
    IL_0018: ldloc.2 
    IL_0019: ldc.i4.2 
    IL_001a: ldstr  "C" 
    IL_001f: stelem.ref 
    IL_0020: ldloc.2 
    IL_0021: ldc.i4.3 
    IL_0022: ldstr  "D" 
    IL_0027: stelem.ref 
    IL_0028: ldloc.2 
    IL_0029: stloc.0 
    IL_002a: ldloc.0 
    IL_002b: callvirt instance int32 [mscorlib]System.Object::GetHashCode() 
    IL_0030: pop 
    IL_0031: ldc.i4.4 
    IL_0032: newarr  [mscorlib]System.String 
    IL_0037: stloc.1 
    IL_0038: ldloc.1 
    IL_0039: ldc.i4.0 
    IL_003a: ldstr  "A" 
    IL_003f: stelem.ref 
    IL_0040: ldloc.1 
    IL_0041: ldc.i4.1 
    IL_0042: ldstr  "B" 
    IL_0047: stelem.ref 
    IL_0048: ldloc.1 
    IL_0049: ldc.i4.2 
    IL_004a: ldstr  "C" 
    IL_004f: stelem.ref 
    IL_0050: ldloc.1 
    IL_0051: ldc.i4.3 
    IL_0052: ldstr  "D" 
    IL_0057: stelem.ref 
    IL_0058: ldloc.1 
    IL_0059: callvirt instance int32 [mscorlib]System.Object::GetHashCode() 
+0

+1 Для теста. –

1

Я провел небольшой тест на instantianting массива, используя синтаксис вы описываете и нашел что создание экземпляров с значениями, отличными от значений по умолчанию, сократилось примерно в 2,2 раза дольше, чем мгновенное значение со значениями по умолчанию.

Когда я переключался и создавал значения по умолчанию, это занимает примерно такое же количество времени.

Действительно, когда я смотрел на декомпиляцию, кажется, что происходит то, что массив инициализируется, а затем заполняется любыми значениями, которые не являются стандартными.

Инстанцирование с не значения по умолчанию:

  bool[] abPrimes = new[] { 
       true, true 
      }; 
0000007e mov   edx,2 
00000083 mov   ecx,79114A46h 
00000088 call  FD3006F0 
0000008d mov   dword ptr [ebp-64h],eax 
00000090 mov   eax,dword ptr [ebp-64h] 
00000093 mov   dword ptr [ebp-54h],eax 
00000096 mov   eax,dword ptr [ebp-54h] 
00000099 cmp   dword ptr [eax+4],0 
0000009d ja   000000A4 
0000009f call  76A9A8DC 
000000a4 mov   byte ptr [eax+8],1 
000000a8 mov   eax,dword ptr [ebp-54h] 
000000ab cmp   dword ptr [eax+4],1 
000000af ja   000000B6 
000000b1 call  76A9A8DC 
000000b6 mov   byte ptr [eax+9],1 
000000ba mov   eax,dword ptr [ebp-54h] 
000000bd mov   dword ptr [ebp-40h],eax 

Инстанцирование со значениями по умолчанию:

bool[] abPrimes2 = new[] { 
       false, false 
      }; 
000000c0 mov   edx,2 
000000c5 mov   ecx,79114A46h 
000000ca call  FD3006F0 
000000cf mov   dword ptr [ebp-68h],eax 
000000d2 mov   eax,dword ptr [ebp-68h] 
000000d5 mov   dword ptr [ebp-54h],eax 
000000d8 mov   eax,dword ptr [ebp-54h] 
000000db mov   dword ptr [ebp-5Ch],eax 
0

Это не возможно, чтобы избежать инициализации каждый слот массива к значению по умолчанию, по крайней мере, в уровне IL.

Строка - это класс, а не структура.

Это означает, что A, B, C, D и сэр могут храниться в любом положении. A, B, C и D могут быть получены из внутреннего пула, что ссылка на объект может быть динамической.

Но я считаю, что JIT может быть достаточно умным, чтобы уменьшить половину этих накладных расходов.

PS. Преждевременная оптимизация - корень всего зла.

Смежные вопросы