Подтвердить что ты не робот

Почему это реализовано как структура?

В System.Data.Linq EntitySet<T> используется несколько структур ItemList<T>, которые выглядят следующим образом:

 internal struct ItemList<T> where T : class
  {
    private T[] items;
    private int count;
    ...(methods)...
  }

(Потребовал меня дольше, чем нужно, чтобы обнаружить это - не мог понять, почему поле объектов в EntitySet<T> не выбрасывало ненужные ссылочные исключения!)

Мой вопрос в том, каковы преимущества реализации этого как структуры над классом?

4b9b3361

Ответ 1

Предположим, что вы хотите сохранить ItemList<T> в массиве.

Выделение массива типов значений (struct) будет хранить данные внутри массива. Если, с другой стороны, ItemList<T> был ссылочным типом (class), внутри массива будут храниться только ссылки на объекты ItemList<T>. Фактические объекты ItemList<T> будут выделены в куче. Для достижения экземпляра ItemList<T> требуется дополнительный уровень косвенности, и поскольку он просто представляет собой массив, объединенный с длиной, более эффективно использовать тип значения.

Struct vs class

После проверки кода для EntitySet<T> я вижу, что массив не задействован. Тем не менее, EntitySet<T> все еще содержит два экземпляра ItemList<T>. Поскольку ItemList<T> является struct, хранилище для этих экземпляров выделяется внутри объекта EntitySet<T>. Если вместо этого использовался class, то EntitySet<T> содержал бы ссылки, указывающие на объекты EntitySet<T>, выделенные отдельно.

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

Ответ 2

Для небольших критических внутренних структур данных, таких как ItemList<T>, мы часто имеем выбор использования либо ссылочного типа, либо типа значения. Если код написан хорошо, переход от одного к другому имеет тривиальное изменение.

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

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

Ответ 3

Возможно, это важно, что... цитата о структуре из здесь

Новая переменная и оригинал переменная поэтому содержит два отдельные копии одних и тех же данных. Изменения, внесенные в одну копию, не влияют на другую копию.

Просто подумайте, не судите меня сложно:)

Ответ 4

На самом деле существует только две причины, по которым когда-либо использовать структуру, и это либо для получения семантики типа значения, либо для повышения производительности.

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

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

Одна из замечательных особенностей такой структуры состоит в том, что вы можете создать массив из них, и вы получите массив пустых списков без необходимости инициализировать каждый список:

ItemList<string>[] = new ItemList<string>[42];

Поскольку элементы массива заполняются нулями, член count будет равен нулю, а член items будет иметь значение null.

Ответ 5

Чисто размышляя здесь:

Поскольку объект довольно мал (имеет только две переменные-члены), он является хорошим кандидатом для того, чтобы сделать его struct, чтобы он передавался как ValueType.

Кроме того, как указывает @Martin Liversage, будучи ValueType, он может быть сохранен более эффективно в больших структурах данных (например, как элемент в массиве), без накладных расходов на наличие отдельного объекта и ссылки на он.