Что лучше для хранилища данных Struct / Classes? - PullRequest
27 голосов
/ 23 декабря 2009

Мы видели много дискуссий в SO относительно класса vs struct в c #. Главным образом заканчиваются выводы о том, что выделение памяти heap / stack . И рекомендует использовать структуры в небольших структурах данных .

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

В соответствии с моим пониманием, я чувствовал, что лучше идти вперед с использованием struct, а не классов для повышения производительности. Потому что это простые структуры данных, которые действуют только как хранилища данных.

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

  • верно ли мое понимание?
  • Я видел, что большинство ORM имеют классы в качестве хранилищ данных. Поэтому я сомневаюсь, что должна быть причина для продолжения занятий вместо структур. что бы это было?

Ответы [ 9 ]

52 голосов
/ 23 декабря 2009

Я бы сделал выбор, основываясь на следующих критериях

  • ссылочный тип против семантики типа значения. Если 2 объекта равны, только если они являются одним и тем же объектом, это указывает на семантику ссылочного типа => класс. Если значение его членов определяет равенство (например, 2 DateTimes равны, если оба представляют один и тот же момент времени, даже если они являются двумя различными объектами), семантика типа значения => struct
  • След памяти объекта. Если объект огромен и часто размещается, то его создание в виде структуры потребляет стек намного быстрее, поэтому я бы предпочел иметь его как класс. Напротив, я бы предпочел избежать штрафа GC для типов малых значений; следовательно сделайте их структурой.
  • Вы можете сделать объект неизменным? Я считаю, что структуры отлично подходят для «ценностных объектов» - из книги DDD.
  • Вы бы столкнулись с некоторыми штрафами за распаковку бокса, основанные на использовании этого объекта? Если да, иди в класс.
10 голосов
/ 26 сентября 2015

Довольно классное, не очень известное преимущество Structs по сравнению с классами заключается в том, что в структурах автоматически реализованы GetHashcode и Equals.
Это очень полезно, когда для словарей требуются ключи

Реализация структуры GetHashcode и Equals основана на двоичном содержимом экземпляров структуры + отражение для ссылочных членов (например, членов String и других экземпляров классов)

Таким образом, следующий код работает для GethashCode / Equals:

public struct Person
{
    public DateTime Birthday { get; set; }
    public int Age{ get; set; }
    public String Firstname { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        Person p1 = new Person { Age = 44, Birthday = new DateTime(1971, 5, 24), Firstname = "Emmanuel" };
        Person p2 = new Person { Age = 44, Birthday = new DateTime(1971, 5, 24), Firstname = "Emmanuel" };
        Debug.Assert(p1.Equals(p2));
        Debug.Assert(p1.GetHashCode() == p2.GetHashCode());
    }
}

Оба утверждения успешны, когда Person является структурой Оба утверждения терпят неудачу, если Person является классом вместо struct

Ссылка: https://msdn.microsoft.com/en-Us/library/2dts52z7%28v=vs.110%29.aspx

С уважением, лучшее кодирование

7 голосов
/ 23 декабря 2009

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

5 голосов
/ 23 декабря 2009

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

Итак. Если вы не знаете, что делаете, просто придерживайтесь уроков.

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

Если я правильно помню, одна из самых больших проблем - это семантика значений структур: их передача приведет к созданию различных объектов (поскольку они передаются по значению). Если вы затем измените какое-либо поле в одном месте, имейте в виду, что во всех других местах поле не изменилось! Вот почему каждый рекомендует неизменность для структур!

РЕДАКТИРОВАТЬ: Для случая, который вы описываете, структуры не будут работать !

4 голосов
/ 06 октября 2011

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

Некоторые люди считают, что носители данных, которые могут изменяться, не должны быть структурами. Я категорически не согласен. Сущности, которые существуют для хранения данных, во многих случаях должны быть структурами , особенно , если они изменчивы. Эрик Липперт много раз писал, что считает изменяемые типы значений злыми (ищите по тегам «изменяемый» и «структура»). Это, безусловно, правда, что .net позволяет выполнять определенные вещи с изменяемыми структурами, чего не следует делать, и не позволяет удобно делать некоторые вещи, которые он должен делать, но структуры POD ("Plain Old Data"), которые не имеют методов мутации, но вместо этого выставляйте все свое состояние через открытые поля, имейте очень полезную согласованность в своем поведении, которое не передается никаким другим типам данных Использование структуры POD может сбить с толку тех, кто не знаком с тем, как они работают, но сделает программу намного более читабельной для любого, кто это сделает.

Рассмотрим, например, следующий код, предполагая, что EmployeeInfoStruct не содержит ничего, кроме типов значений и неизменных типов классов, таких как String:

[employeeInfoStruct is a struct containing the following field]
public Decimal YearlyBonus;

[someEmployeeContainer is an instance of a class which includes the following method]
EmployeeInfoStruct GetEmployeeInfo(String id);  // Just the signature--code is immaterial

[some other method uses the following code]
EmployeeInfoStruct anEmployee = someEmployeeContainer.GetEmployeeInfo("123-45-6789");
anEmployee.YearlyBonus += 100;

Эрик Липперт жалуется, что приведенный выше код изменит значение в anEmployee, но это изменение не повлияет на контейнер. Я хотел бы предположить, что это хорошо - любой, кто знает, как работает структура, может взглянуть на приведенный выше код и знает, что запись в переменную структуры повлияет на эту переменную, но не повлияет на что-либо еще, если в дальнейшем программа не использует какой-либо другой метод (возможно, SetEmployeeInfo) для хранения этой переменной где-либо.

Теперь замените EmployeeInfoStruct на EmployeeInfoClass, который имеет свойство чтения / записи типа YearlyBonus. Используя только приведенную выше информацию, что можно сказать об отношениях между записями в someEmployeeContainer и anEmployee? В зависимости от реализаций класса anEmployee (который, если EmployeeInfoClass не является закрытым, может или не может быть на самом деле EmployeeInfoClass) и someEmployeeContainer, отношения между объектами могут быть любыми. Пишет кому-то:

  1. не влияет на других
  2. Обновите другой «естественным» способом
  3. Повредить другого каким-то образом

С структурами, не содержащими ничего, кроме полей типов значений или неизменяемых классов, семантика всегда будет # 1. Чтобы узнать это, не нужно смотреть ни на код самой структуры, ни на код контейнера. Напротив, если anEmployee.Salary или someEmployeeContainer.GetEmployee являются виртуальными, невозможно реально знать, какой будет семантика.

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

3 голосов
/ 23 декабря 2009

Комментарий о неизменности структур верен. И это то, что может вас укусить. Вы можете определить структуры с помощью установщиков полей, но при изменении значения поля создается новый экземпляр. Таким образом, если вы удерживаете ссылку на старый объект, он все равно будет ссылаться на старое значение. По этой причине я не люблю использовать изменяемые структуры, поскольку это может привести к появлению тонких и сложных ошибок (особенно если вы используете сложные составные операторы).

С другой стороны, есть много веских причин использовать классы также с неизменным состоянием (думаю строка).

2 голосов
/ 23 декабря 2009

Я думаю, у вас правильная идея. Структуры сделаны, чтобы подражать типам данных. Они основаны на ценностях, а не на основе ссылок. Если вы посмотрите документацию MSDN для большинства базовых классов данных (int, double, decimal и т. Д.), То все они основаны на структурах. При этом, однако, структуры не должны быть чрезмерно использованы по той же самой причине. Пространство для хранения всего, что находится в этой структуре, выделяется, как только оно создается, а классы просто выделяют место для ссылки на все внутри. Если данные находятся в достаточно маленьких порциях, где это не является проблемой, тогда лучше всего использовать структуры. Если это проблема, идите с классами. Если вы не знаете, то лучше всего придерживаться того, с чем вы знакомы.

2 голосов
/ 23 декабря 2009

Я помню один совет, данный на MSDN, что структура не должна превышать 16 или 21 байт. Ищу ссылку, но пока не могу ее найти.

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

0 голосов
/ 04 июля 2013

Если у вас низкие требования к задержке и МНОГО объектов, медленная сборка мусора может стать проблемой. В этом случае структура может быть очень полезной, поскольку сборщику мусора не нужно сканировать иерархию типов значений, если типы значений не содержат никаких ссылочных типов.

Вы можете найти тест здесь: http://00sharp.wordpress.com/2013/07/03/a-case-for-the-struct/

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