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

Когда структуры лучше классов?

Дубликат: Когда использовать struct в С#?

Есть ли практические причины использовать структуры вместо некоторых классов в Microsoft.NET 2.0/3.5?

"В чем разница между структурами и классами?" - это, наверное, самый популярный вопрос в intrviews для вакансий разработчика .NET. Единственный ответ, который, по мнению интервьюера, является правильным, - "структуры распределяются по стеклу, а классы распределяются по куче", и никаких дополнительных вопросов об этом не задано.

Некоторые поисковые запросы Google показали, что:

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

  • размер блока данных меньше, чем 16 байт
  • нет обширного бокса/распаковкиЭлементы структуры
  • почти неизменяемы.
  • весь набор данных невелик (в противном случае мы получаем переполнение стека)

(пожалуйста, исправьте/добавьте в этот список, если он неверен или не заполнен)

Насколько мне известно, наиболее типичные коммерческие проекты (ERM, accouting, решения для банков и т.д.) не определяют даже одну структуру, все пользовательские типы данных определяются как классы. Что-то не так или, по крайней мере, несовершенно в этом подходе?

ПРИМЕЧАНИЕ: вопрос о бизнес-приложениях, запущенных на заводе, не перечисляет "необычные" случаи, такие как разработка игр, анимация в реальном времени, обратная совместимость (COM/Interop), неуправляемый код и т.д. эти ответы уже по такому же вопросу:

Когда использовать struct?

4b9b3361

Ответ 1

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

Ответ 2

Насколько мне известно, наиболее типичные коммерческие проекты (ERM, accouting, решения для банков и т.д.) не определяют даже одну структуру, все пользовательские типы данных определяются как классы. Что-то не так или, по крайней мере, несовершенно в этом подходе?

Нет! С этим все в порядке. Общее правило должно быть всегда использовать объекты по умолчанию. В конце концов, мы говорим об объектно-ориентированном программировании по причине, а не к структурно-ориентированной программированию (сами структуры не имеют некоторых принципов OO, таких как Inheritance and Abstraction).

Однако структуры иногда лучше, если:

  • Вам нужен точный контроль над объемом используемой памяти (структуры используют (в зависимости от размера) немного, чтобы FAR меньше памяти, чем объекты.
  • Вам нужно точное управление макетом памяти. Это особенно важно для взаимодействия с Win32 или другими родными API.
  • Вам нужна самая быстрая скорость. (Во многих сценариях с большими наборами данных вы можете получить приличное ускорение при правильном использовании структур).
  • Вам нужно тратить меньше памяти и иметь большие объемы структурированных данных в массивах. Особенно в сочетании с массивами вы можете получить огромное количество экономии памяти со структурами.
  • Вы активно работаете с указателями. Тогда структуры предлагают множество интересных характеристик.

Ответ 3

IMO самым важным вариантом использования являются большие массивы небольших составных объектов. Представьте себе массив, содержащий 10 ^ 6 комплексных чисел. Или 2d-массив, содержащий 1000x1000 24-битных значений RGB. Использование struct вместо классов может иметь огромное значение в таких случаях.

EDIT: Чтобы уточнить: предположим, что у вас есть структура

struct RGB 
{
   public byte R,G,B;
}

Если вы объявляете массив значений RGB 1000x1000, этот массив будет занимать ровно 3 МБ памяти, поскольку типы значений сохраняются в строке.

Если вы использовали класс вместо struct, массив будет содержать 1000000 ссылок. Только это займет 4 или 8 МБ (на 64-битной машине) памяти. Если вы инициализировали все элементы с отдельными объектами, чтобы вы могли изменять значения отдельно, вы бы набрали 1000000 объектов, которые кружатся вокруг управляемой кучи, чтобы поддерживать работу GC. Каждый объект имеет накладные расходы (IIRC) из 2-х ссылок, т.е. Объекты будут использовать 11/19 МБ памяти. В общем, в 5 раз больше памяти, чем простая версия структуры.

Ответ 4

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

Это, конечно, предполагает, что мы говорим о безопасном, управляемом коде.

Ответ 5

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

struct Aggregate1
{
    int A;
}

struct Aggregate2
{
    Aggregate1 A;
    Aggregate1 B;
}

Обратите внимание, что если Aggregate1 был классом, вам пришлось бы вручную инициализировать поля в Aggregate2...

Aggregate2 ag2 = new Aggregate2();
ag2.A = new Aggregate1();
ag2.B = new Aggregate1();

Это явно не требуется, если Aggregate1 является структурой... это может оказаться полезным, когда вы создаете иерархию класса/структуры с явной целью сериализации/десериализации с помощью XmlSerializer Многие, казалось бы, загадочные исключения исчезнет, ​​просто используя структуры в этом случае.

Ответ 6

Если целью типа является связывание небольшого фиксированного набора независимых значений вместе с клейкой лентой (например, координаты точки, ключа и связанного с ним значения перечисляемой словарной статьи, матрицы преобразования 2d с двумя элементами, и т.д.), лучшее представление с точки зрения эффективности и семантики, вероятно, будет изменчивой структурой открытого поля. Обратите внимание, что это представляет собой совершенно другой сценарий использования из того случая, когда структура представляет собой единую единую концепцию (например, Decimal или DateTime), а совет Microsoft, когда использовать структуры, дает советы, которые применимы только к последнему, Стиль "неизменной" структуры, которую описывает Microsoft, действительно подходит для представления единой единой концепции; если нужно представить небольшой фиксированный набор независимых значений, то подходящая альтернатива не является неизменяемым классом (который предлагает более низкую производительность), а также изменчивым классом (который во многих случаях будет предлагать неверную семантику), а скорее структурой с открытым полем (который при правильном использовании - обеспечивает превосходную семантику и производительность). Например, если у вас есть структура MyTransform, которая содержит матрицу преобразования 2d, то такой метод, как:

static void Offset(ref it, double x, double y)
{
  it.dx += x;
  it.dy += y;
}

быстрее и понятнее, чем

static void Offset(ref it, double x, double y)
{
  it = new Transform2d(it.xx, int.xy, it.yx, it.yy, it.dx+x, it.dy+y);
}

или

Transform2d Offset(double dx, double dy)
{
  it = new Transform2d(xx, xy, yx, yy, dx+x, dy+y);
}

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

Ответ 7

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

В доменном дизайне http://www.infoq.com/minibooks/domain-driven-design-quickly существует несколько параллели между объектами/классами и объектами Value/Структура. Объекты в DDD - это элементы внутри бизнес-домена, идентификация которого должна отслеживаться с идентификатором, например. CustomerId, ProductId и т.д. Объекты Value - это объекты, значения которых нам могут быть интересны, но чью личность мы не отслеживаем с помощью идентификатора, например Price или OrderDate. Объекты изменяются в DDD, за исключением их поля Identity, тогда как объекты Value не имеют идентификатора.

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

Ответ 8

Когда-нибудь, вы просто хотите передавать данные между компонентами, тогда структура лучше, чем класс. например Объект передачи данных (DTO), который переносит данные только.