Сигнатура индексатора массива возвращает объект - это коробка?

Я наткнулся на факт, что индексатор this[int index] { get; } работает по-разному для массив структур, чем для списка структур. А именно, что индексатор в случае T[] возвращает ссылку на элемент в массиве, тогда как индексатор в случае List<T> возвращает копию элемента.

Это очень большая разница в семантике и производительности, и я рад, что T[] позволяет нам обойти ограничение производительности List<T>.

Однако я озадачен фактической реализацией. код для Array в справочных источниках .net выглядит следующим образом:

Object IList.this[int index] {
    get { return GetValue(index); }
    set { SetValue(value, index); }
}

Где GetValue определяется следующим образом:

public unsafe Object GetValue(int index)
{
    if (Rank != 1)
       throw new ArgumentException(Environment.GetResourceString("Arg_Need1DArray"));
    Contract.EndContractBlock();
    TypedReference elemref = new TypedReference();
    InternalGetReference(&elemref, 1, &index);
    return TypedReference.InternalToObject(&elemref);
}

Тип возврата индексатора — Object, подразумевая, что упаковка будет иметь место.

Итак, мой вопрос: могу ли я быть уверен, что при доступе к элементу T[], где T является структурой, не произойдет бокс?

Я предполагаю, что компилятор и/или CLR специально обрабатывают массив и на самом деле не беспокоятся о сигнатуре индексатора. Это правильно? Где-то есть более полное обсуждение этого?


person bright    schedule 07.09.2016    source источник
comment
IList.SomeMethod — это неявная реализация интерфейса. Это способ сообщить, что этот метод существует, если объект классифицируется как IList. Он будет использоваться только в том случае, если вы специально запросите его, например. в случае индексатора ((IList)someArray)[x]. Прямой доступ к индексатору массива (например, someArray[x]) — это другое дело, вы не найдете исходники для какого-либо метода, потому что их нет.   -  person Sinatr    schedule 07.09.2016


Ответы (1)


А именно, индексатор в случае T[] возвращает ссылку на элемент внутри массива.

Не совсем. Дело в том, что для массивов нет индексатора — вместо этого выражение element-access представляет доступ к массиву, а не к элементу (разделы 7.6.6.1 и 7.6.6.2 спецификации C# 5 соответственно). .

Между ними есть очень существенная разница: в частности, доступ к массиву классифицируется как переменная, тогда как доступ к индексатору классифицируется как значение.

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

Итак, мой вопрос: могу ли я быть уверен, что при доступе к элементу T[], где T является структурой, не произойдет бокс?

Если вы обращаетесь к нему как T[], конечно. Индексатор, на который вы смотрели, используется только тогда, когда вы просматриваете массив как IList. Итак, если вы используете:

IList array = new int[2];
object x = array[0];

тогда да, это будет значение... но если вы напишете

int[] array = new int[2];
int x = array[0];

тогда этого не будет, и он вообще не будет обращаться к этому коду индексатора или методу GetValue.

person Jon Skeet    schedule 07.09.2016
comment
Другой способ взглянуть на это: System.Array похож на базовый тип всех массивов. Реализация IList.this[int index] в этом базовом типе существует, поэтому массивы будут реализовывать System.Collections.IList, а не для обычного доступа к элементам. - person Jacob Krall; 07.09.2016
comment
Большое спасибо. Дополнительный вопрос: есть ли в Array.cs что-нибудь, что выполняется, когда я вызываю array[index]? Или все это реализовано непосредственно в среде CLR? - person bright; 07.09.2016
comment
@bright: Насколько мне известно, все в CLR. Есть IL специально для доступа к массиву, хотя я не могу навскидку вспомнить имена операций. - person Jon Skeet; 07.09.2016
comment
@JonSkeet, нашел - ldelem.‹type›. Спасибо. - person bright; 07.09.2016