Зачем нам нужен статический частный массив для инициализации других нестатических полей частного массива?

Если вы заглянете внутрь класса Stack<T> из .NET 4.0, вы заметите, что есть закрытое статическое поле "emptyArray", которое используется внутри конструкторов для инициализации реального закрытого поля "массив".

private T[] array;
private static T[] emptyArray;
private int size;
private int version;

static Stack()
{
    Stack<T>.emptyArray = new T[0];
}

public Stack()
{
    array = Stack<T>.emptyArray;
    size = 0;
    version = 0;
}

Почему бы просто не поставить this.array = new T[0]; ? А также почему для полей размера и версии размещены штрихи инициализации, если вы опустите эти строки, они все равно будут инициализированы значениями по умолчанию (0).


person Grief Coder    schedule 31.08.2010    source источник


Ответы (1)


Это потому, что в противном случае каждый Stack получает свой собственный экземпляр new T[0]. Теперь все они ссылаются на один и тот же экземпляр: тот, который объявлен статическим. Предположим, вы объявляете 1000 Stack<string>. Все они имеют ссылку на один объект string[0]. Если бы вы объявили пустой массив внутри конструктора, у вас было бы 1000 экземпляров string[0], по одному для каждого Stack<string>. Так что это из соображений производительности.

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

person Ronald Wildenberg    schedule 31.08.2010
comment
Каждый Stack уже получает свой T[0], когда конструктор вызывается array = Stack<T>.emptyArray, не так ли? - person Grief Coder; 31.08.2010
comment
Нет, они получают ссылку (только указатель) на один и тот же экземпляр. - person Ronald Wildenberg; 31.08.2010
comment
Я думаю, что это может быть соглашением о кодировании, чтобы нигде не зависеть от значений по умолчанию, а делать их явными. Другая возможность заключается в том, что Reflector просто показывает это таким образом, потому что базовый код IL присваивает явные значения «по умолчанию». Это означало бы, что компилятор добавляет эти операторы. В конце концов, каждая переменная должна иметь значение, чтобы задача компилятора заключалась в назначении значений по умолчанию. Вы можете проверить это, написав небольшой класс, который явно не присваивает значения по умолчанию, скомпилируйте его и откройте в Reflector. - person Ronald Wildenberg; 31.08.2010
comment
Нет, каждый стек получает ссылку на эту единственную версию пустого массива. Существует только один мыслимый тип пустого массива ‹T› (который, к удивлению, пустой), поэтому emptyArray является одноэлементным из-за соображений производительности. То же самое должно быть для истинных, ложных, небольших целых чисел (по крайней мере, в java это ‹ 256 или около того). Это уменьшает использование памяти. - person atamanroman; 31.08.2010
comment
Я только что скомпилировал тестовое приложение, открыл его в Reflector. Значения по умолчанию там не инициализируются. - person Grief Coder; 31.08.2010
comment
Интересно. В этом случае я думаю, что это соглашение о кодировании в Microsoft. В этом есть смысл, вы никогда не ошибетесь в значении переменной. Но я не уверен на 100% в этом.. - person Ronald Wildenberg; 31.08.2010