Почему это реализовано как структура? - PullRequest
43 голосов
/ 01 июня 2011

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

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

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

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

Ответы [ 5 ]

34 голосов
/ 01 июня 2011

Предположим, что вы хотите сохранить 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> объекты, выделенные отдельно.

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

9 голосов
/ 01 июня 2011

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

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

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

6 голосов
/ 01 июня 2011

Может быть важно, чтобы ... цитата о структуре из здесь

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

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

5 голосов
/ 01 июня 2011

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

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

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

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

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

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

2 голосов
/ 01 июня 2011

Здесь чисто предположения:

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

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

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