System.Array выполняет бокс для типов значений или нет?
Я недавно сделал некоторые грубые измерения производительности на List<>
против []
для массива небольших структур. System.Array, казалось, выиграл руки вниз, поэтому я пошел с этим.
Меня только что осенило, что System.Array содержит типы объектов, поэтому, несомненно, заполнение его структурами вызовет бокс?
Однако в записи MSDN для System.Array говорится:
В.NET Framework версии 2.0 класс Array реализует
System.Collections.Generic.IList<T>
,System.Collections.Generic.ICollection<T>
, а такжеSystem.Collections.Generic.IEnumerable<T>
универсальные интерфейсы. Реализации предоставляются массивам во время выполнения и, следовательно, не видны инструментам сборки документации. В результате универсальные интерфейсы не появляются в синтаксисе объявления для класса Array, и нет никаких справочных разделов для членов интерфейса, которые доступны только путем приведения массива к универсальному типу интерфейса (явные реализации интерфейса).
Значит ли это, что бокс не происходит в конце концов? (И объяснил бы результаты моей работы)
1 ответ
Нет использования массива не бокс, если вы используете индексную нотацию. например
new int[2];
x=[1]=3;
Компилируется в следующий IL (обратите внимание, что номера строк не имеют значения, поскольку они взяты из некоторого другого фрагмента кода)
IL_0011: ldc.i4.2
IL_0012: newarr System.Int32
IL_0017: stfld Int32[] x
IL_001c: ldarg.0
IL_001d: ldfld Int32[] x
IL_0022: ldc.i4.1
IL_0023: ldc.i4.3
IL_0024: stelem.i4
Для языков, которые не могут использовать индексатор (и я действительно не знаю, существуют они или нет), 2 других метода создаются во время компиляции для массивов.
Это создает эти публичные методы:
public int Get(int index)
public void Set(int index,int value)
Эти методы также не упаковываются и обычно не доступны через C#. (Не спрашивайте меня, почему они являются публичными методами). Вы можете выполнить их, используя IL или создавая делегатов для них. Они медленнее, так как вы вынуждены выполнять callvirt для вызова этих методов.
Семейство stelem.* И ldelem.* Используется для обработки хранения в строго типизированный тип массива. При использовании дженериков обычно добавляются следующие префиксы constrained
или же readonly
при использовании T[]
, stelem.*
тип обычно не проверяет тип. Например, используя stelem.i4
быстрее, чем с помощью stelem.any Int32
если вы не префикс это readonly
потому что в противном случае он вызывает проверку типа.
Теперь проверка типов ПОЛНОСТЬЮ бесполезна для массивов значений типа, если они не являются ковариантными!
Поскольку среда выполнения генерирует одномерный массив, начинающийся с нулевого типа (называемый SZ_array или векторный тип), они изначально известны.
Для них есть семейство кодов il op: newarr
,stelem.*
,ldelem.*
,ldlen
и т.п.
List<T>
Тип использует T[]
для его резервного хранилища в Microsoft реализации BCL. List<T>
не бокс. Независимо от использования списка или массива вы храните вещи в массиве.