28 Вопрос: Когда использовать структуру?

вопрос создан в Wed, Jan 11, 2017 12:00 AM

Когда вы должны использовать struct, а не class в C #? Моя концептуальная модель состоит в том, что структуры используются во времена, когда элемент является просто коллекцией типов значений . Способ логически объединить их все в единое целое.

Я сталкивался с этими правилами. "Архивировано с исходного сайта: www.johnnycantcode.com/Post/C_Classes_vs._Structs"> здесь :

  • Структура должна представлять один значение.
  • Структура должна иметь память занимает менее 16 байт.
  • Структура не должна быть изменена после создание.

Эти правила работают? Что означает семантически структура?

    
1313
  1. System.Drawing.Rectangle нарушает все эти три правила.
    2009-02-06 17: 52: 39Z
  2. Есть довольно много коммерческих игр, написанных на C #, дело в том, что они используются для оптимизированного кода
    2009-02-06 18: 01: 09Z
  3. Структуры обеспечивают лучшую производительность, когда у вас есть небольшие коллекции типов значений, которые вы хотите сгруппировать вместе. Это происходит постоянно при программировании игры, например, вершина в трехмерной модели будет иметь позицию, текстурную координату и нормаль, она также обычно будет неизменной. У одной модели может быть пара тысяч вершин или дюжина, но структуры обеспечивают меньшие накладные расходы в целом в этом сценарии использования. Я проверил это через мой собственный дизайн двигателя.
    2010-07-21 18: 26: 15Z
  4. 2012-03-02 18: 34: 20Z
  5. @ ChrisW Я вижу, но разве эти значения не представляют собой прямоугольник, то есть "одиночное" значение? Как и Vector3D или Color, они также содержат несколько значений, но я думаю, что они представляют отдельные значения?
    2015-07-29 03: 09: 40Z
28 ответов                              28                         

Источник, на который ссылается OP, заслуживает доверия ... но как насчет Microsoft - какова позиция по использованию struct? Я искал дополнительное обучение у Microsoft , и вот что я нашел:

  

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

     

Не определяйте структуру, если тип не имеет всех следующих характеристик:

     
  1. Логически представляет одно значение, подобное примитивным типам (целое, двойное и т. д.).
  2.   
  3. Размер экземпляра меньше 16 байт.
  4.   
  5. Он неизменен.
  6.   
  7. Это не должно быть часто в штучной упаковке.
  8.   

Microsoft постоянно нарушает эти правила

Хорошо, № 2 и № 3 в любом случае. Наш любимый словарь имеет 2 внутренних структуры:

 
[StructLayout(LayoutKind.Sequential)]  // default for structs
private struct Entry  //<Tkey, TValue>
{
    //  View code at *Reference Source
}

[Serializable, StructLayout(LayoutKind.Sequential)]
public struct Enumerator : 
    IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, 
    IDictionaryEnumerator, IEnumerator
{
    //  View code at *Reference Source
}

* Справочный источник

Источник 'JonnyCantCode.com' получил 3 из 4 - вполне простительно, так как # 4, вероятно, не будет проблемой. Если вы обнаружите, что занимаетесь структурой, переосмыслите свою архитектуру.

Давайте посмотрим, почему Microsoft будет использовать эти структуры:

  1. Каждая структура Entry и Enumerator представляет отдельные значения.
  2. Скорость
  3.  Entry никогда не передается в качестве параметра за пределы класса Dictionary. Дальнейшие исследования показывают, что для удовлетворения реализации IEnumerable, словарь uses структура Enumerator, которую она копирует каждый раз при запросе перечислителя ... имеет смысл.
  4. Внутри класса Dictionary. Enumerator является общедоступным, поскольку словарь является перечисляемым и должен иметь равный доступ к реализации интерфейса IEnumerator, например IEnumerator getter.

Обновление . Кроме того, следует понимать, что когда структура реализует интерфейс - как это делает Enumerator - и приводится к этому реализованному типу, структура становится ссылочным типом и перемещается в кучу. Внутри класса Dictionary, перечислитель является по-прежнему типом значения. Однако, как только метод вызывает GetEnumerator(), возвращается ссылочный тип IEnumerator.

Здесь мы не видим каких-либо попыток или доказательств необходимости сохранять неизменяемыми структуры или поддерживать размер экземпляра не более 16 байт:

  1. Ничто в вышеприведенных структурах не объявлено readonly - не неизменным
  2. Размер этой структуры может превышать 16 байт.
  3.  Entry имеет неопределенный срок службы (от Add() до Remove(), Clear() или сборщик мусора);

И ...  4. Обе структуры хранят TKey и TValue, которые, как мы все знаем, вполне могут быть ссылочными типами (дополнительная информация о бонусе)

Несмотря на то что ключи хешируются, словари работают быстро, потому что создание структуры происходит быстрее, чем ссылочный тип. Здесь у меня есть Dictionary<int, int>, в котором хранится 300 000 случайных целых чисел с последовательно увеличенными ключами.

  

Вместимость: 312874
  MemSize: 2660827 байт
  Завершено Изменение размера: 5 мс
  Общее время заполнения: 889 мс

Capacity : количество элементов, доступных до изменения размера внутреннего массива.

MemSize : определяется путем сериализации словаря в MemoryStream и получения длины в байтах (достаточно точной для наших целей).

Completed Resize : время, необходимое для изменения размера внутреннего массива с 150862 до 312874 элементов. Когда вы понимаете, что каждый элемент последовательно копируется через Array.CopyTo(), это не так уж и плохо.

Общее время для заполнения : предположительно искажен из-за регистрации и события OnResize, которые я добавил в источник; Тем не менее, по-прежнему впечатляет заполнить 300 тысяч целых чисел при изменении размера в 15 раз во время операции. Просто из любопытства, сколько будет общего времени, чтобы заполнить, если бы я уже знал емкость? 13 мс

Итак, что если Entry был классом? Будут ли эти времена или показатели действительно сильно отличаться?

  

Вместимость: 312874
  MemSize: 2660827 байт
  Завершено Изменение размера: 26 мс
  Общее время заполнения: 964 мс

Очевидно, большая разница заключается в изменении размера. Есть ли разница, если словарь инициализируется с Capacity? Недостаточно беспокоиться о ... 12 мс .

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

 
/*
 *  Added to satisfy initialization of entry elements --
 *  this is where the extra time is spent resizing the Entry array
 * **/
for (int i = 0 ; i < prime ; i++)
{
    destinationArray[i] = new Entry( );
}
/*  *********************************************** */  

Причину, по которой мне пришлось инициализировать каждый элемент массива Entry в качестве ссылочного типа, можно узнать по адресу MSDN: Проектирование конструкций . Короче говоря:

  

Не предоставляйте конструктор по умолчанию для структуры.

     

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

     

Некоторые компиляторы, такие как компилятор C #, не позволяют структурам   есть конструкторы по умолчанию.

На самом деле все довольно просто, и мы позаимствуем у Три закона робототехники Азимова : р>

  1. Структура должна быть безопасной для использования
  2. Структура должна эффективно выполнять свою функцию, если только это не нарушит правило # 1
  3. Структура должна оставаться неизменной во время ее использования, если только ее уничтожение не требуется для удовлетворения правила # 1

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

    
582
2015-06-11 13: 53: 06Z
  1. Что касается правил Microsoft, то, как представляется, правило об неизменности разработано таким образом, чтобы препятствовать использованию типов значений таким способом, каким• их поведение будет отличаться от поведения ссылочных типов, несмотря на тот факт, что кусочно-изменяемая семантика значений может быть полезной . Если наличие типа является кусочно-изменяемым, с ним будет легче работать, и если места хранения типа должны быть логически отделены друг от друга, тип должен быть «изменяемой» структурой.
    2012-07-23 18: 03: 56Z
  2. 2012-10-03 14: 35: 21Z
  3. Тот факт, что многие типы Microsoft нарушают эти правила, не представляет проблемы с этими типами, а скорее указывает на то, что правила не должны применяться ко всем типам структуры. Если структура представляет отдельную сущность [как с Decimal или DateTime], то, если она не будет соблюдать другие три правила, она должна быть заменена классом. Если структура содержит фиксированный набор переменных, каждая из которых может содержать любое значение, которое будет допустимо для ее типа [например, Rectangle], то он должен соблюдать различные правила, некоторые из которых противоречат правилам для «однозначных» структур.
    2013-03-06 16: 45: 46Z
  4. @ IAbstract: некоторые люди оправдывают тип записи Dictionary на основании того, что это только внутренний тип, производительность считается более важной, чем семантика, или какое-то другое оправдание. Я хочу сказать, что для типа, подобного Rectangle, его содержимое должно отображаться в виде полей, которые можно редактировать индивидуально, не "потому что" преимущества в производительности перевешивают возникающие семантические недостатки, а потому, что тип семантически представляет фиксированный набор независимых значений и поэтому изменяемая структура является более производительной и семантически превосходной .
    2013-03-06 18: 18: 40Z
  5. @ supercat: я согласен ... и весь смысл моего ответа заключался в том, что «руководящие принципы» довольно слабые, и структуры должны использоваться с полным знанием и пониманием поведения. Смотрите мой ответ по изменяемой структуре здесь: stackoverflow.com/questions/8108920/…
    2013-03-06 18: 43: 12Z

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

    
153
2009-02-06 17: 50: 16Z
  1. Это всего лишь одна оговорка. Также следует учитывать «снятие» значений-типов и случаев, таких как (Guid)null (допустимо приводить ноль к ссылочному типу), среди прочего.
    2011-01-27 18: 34: 49Z
  2. дороже, чем в C /C ++? в C ++ рекомендуется передавать объекты по значению
    2013-07-08 20: 53: 36Z
  3. @ IonTodirel Разве это не из соображений безопасности памяти, а не производительности? Это всегда компромисс, но передача 32 B стека всегда (TM) будет медленнее, чем передача ссылки 4 B регистром. Однако также обратите внимание, что использование «value /reference» немного отличается в C # и C ++ - когда вы передаете ссылку на объект, вы все равно передаете по значению, даже если вы передаете ссылку (вы передаете значение ссылки, а не ссылку на ссылку, в основном). Это не значение семантики ,но технически это «передача по значению».
    2015-11-23 13: 25: 29Z
  4. @ Luaan Копирование - это только один аспект затрат. Дополнительная косвенность из-за указателя /ссылки также стоит за доступ. В некоторых случаях структура может даже быть перемещена и, следовательно, даже не должна быть скопирована.
    2016-02-19 16: 11: 41Z
  5. @ Onur, это интересно. Как вы «двигаетесь» без копирования? Я думал, что инструкция asm "mov" на самом деле не "перемещается". Копирует.
    2017-07-27 18: 15: 26Z

Я не согласен с правилами, приведенными в оригинальном посте. Вот мои правила:

1) Вы используете структуры для производительности при хранении в массивах. (см. также Когда ответ структурируется? )

2) Они нужны вам при передаче кода структурированных данных в /из C /C ++

3) Не используйте структуры, если они вам не нужны:

  • Они ведут себя иначе, чем "обычные объекты" ( ссылочные типы ) при назначении и при передаче в качестве аргументов, которые могут привести к неожиданному поведению; это особенно опасно, если человек, смотрящий на код не знаю, что они имеют дело со структурой.
  • Они не могут быть унаследованы.
  • Передача структур в качестве аргументов дороже, чем классов.
142
2017-05-23 12: 18: 26Z
  1. + 1 Да, я полностью согласен с № 1 (это огромное преимущество при работе с такими вещами, как изображения и т. д.) и для указания из-за того, что они отличаются от «обычных объектов», и существует способ узнать это , кроме как с помощью имеющихся знаний или изучения самого типа. Кроме того, вы не можете привести нулевое значение к типу структуры :-) На самом деле это один из случаев, когда я почти хотел бы, чтобы был какой-то «венгерский» для неосновных типов значений или обязательный ' ключевое слово struct 'на сайте объявления переменных.
    2011-01-27 18: 36: 57Z
  2. @ pst: Это правда, что нужно знать что-то, это struct, чтобы знать, как оно будет себя вести, но если что-то struct с открытыми полями, это все одно должен знать. Если объект предоставляет свойство типа открытого поля-структуры, и если код считывает эту структуру в переменную и изменяет ее, можно с уверенностью предсказать, что такое действие не повлияет на объект, свойство которого было прочитано, до тех пор, пока структура не будет записана назад. Напротив, если свойство было изменяемым типом класса, его чтение и изменение может привести к обновлению базового объекта, как и ожидалось, но ...
    2012-07-24 21: 33: 50Z
  3. ... это может также привести к тому, что ничего не изменится, или это может изменить или повредить объекты, которые никто не намеревался изменить. Наличие кода, семантика которого гласит: «Измените эту переменную так, как вам нравится; изменения не будут делать ничего, пока вы явно не сохраните их где-то», - кажется более понятным, чем наличие кода, который говорит: «Вы получаете ссылку на некоторый объект, который может быть использован совместно с любым числом. других ссылок, или могут вообще не передаваться; вам нужно выяснить, у кого еще могут быть ссылки на этот объект, чтобы знать, что произойдет, если вы его измените. "
    2012-07-24 21: 40: 04Z
  4. Пятно с # 1. Список, полный структур, может втиснуть гораздо больше релевантных данных в кэши L1 /L2, чем список, полный ссылок на объекты (для правильной структуры размера).
    2015-09-11 19: 00: 02Z
  5. Наследование редко является правильным инструментом для работы, и слишком много рассуждений о производительности без профилирования - плохая идея. Во-первых, структуры могут быть переданы по ссылке. Во-вторых, передача по ссылке или по значению редко является значительной проблемой производительности. Наконец, вы не учитываете дополнительное выделение кучи и сборку мусора.это должно иметь место для класса. Лично я предпочитаю рассматривать структуры как простые старые данные, а классы - как вещи, которые делают вещи (объекты), хотя вы также можете определять методы для структур.
    2015-11-20 18: 11: 49Z

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

Изменить

Не знаю, почему люди опровергают это, но это правильное замечание, и оно было сделано до того, как ОП разъяснил его вопрос, и это самая фундаментальная основная причина для структуры.

Если вам нужна ссылочная семантика, вам нужен класс, а не структура.

    
84
2013-08-28 10: 10: 45Z
  1. Это знают все. Похоже, он ищет не просто ответ "структура является типом значения".
    2009-02-06 17: 42: 09Z
  2. Не все это знают. Это явно один случай.
    2009-02-06 17: 46: 48Z
  3. Это наиболее простой случай, и его следует указывать всем, кто читает этот пост и не знает этого.
    2009-02-06 17: 55: 16Z
  4. Не то, чтобы этот ответ не был правдивым; это очевидно. Дело не в этом.
    2009-02-06 18: 02: 32Z
  5. @ Джош: Для тех, кто его еще не знает, просто сказать, что это недостаточный ответ, поскольку вполне вероятно, что они тоже не знают, что это значит. .
    2009-02-06 18: 03: 10Z

В дополнение к ответу "это значение" существует один конкретный сценарий использования структур, когда вы знаете , что у вас есть набор данных, вызывающий мусор проблемы с коллекцией, и у вас есть много объектов. Например, большой список /массив экземпляров Person. Естественной метафорой здесь является класс, но если у вас есть большое количество долгоживущих экземпляров Person, они могут в конечном итоге засорить GEN-2 и вызвать остановку GC. Если сценарий оправдывает это, один из возможных подходов состоит в том, чтобы использовать массив (не список) Person structs , то есть Person[]. Теперь, вместо миллионов объектов в GEN-2, у вас есть отдельный кусок в LOH (я предполагаю, что здесь нет строк и т. Д., То есть чистое значение без каких-либо ссылок). Это имеет очень небольшое влияние ГХ.

Работать с этими данными неудобно, так как данные, вероятно, имеют слишком большой размер для структуры, и вы не хотите постоянно копировать жирные значения. Однако доступ к нему напрямую в массиве не копирует структуру - она ​​на месте (в отличие от индексатора списка, который копирует). Это означает большую работу с индексами:

 
int index = ...
int id = peopleArray[index].Id;

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

 
void Foo(ref Person person) {...}
...
Foo(ref peopleArray[index]);

Опять же, это на месте - мы не скопировали значение.

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

    
58
2011-10-22 12: 14: 22Z
  1. + 1 Интересный ответ. Хотели бы вы поделиться реальными анекдотами о таком подходе?
    2012-10-15 16: 22: 43Z
  2. @ Джордао на мобильном, но поищите в Google: + gravell + "assault by GC"
    2012-10-15 17: 18: 54Z
  3. Большое спасибо. Я нашел его здесь .
    2012-10-15 19: 15: 35Z
  4. @ MarcGravell Почему вы упомянули: использовать массив (не список) ? List Я считаю, использует Array за кулисами. нет?
    2014-02-11 15: 39: 13Z
  5. @ RoyiNamir Мне тоже было любопытно, но я полагаю, что ответ находится во втором абзаце ответа Марка. «Однако доступ к нему напрямую в массиве не копирует структуру - она ​​на месте (в отличие от индексатора списка, который копирует)».
    2014-09-30 12: 00: 59Z

Из спецификации языка C # :

  

1,7 Структуры

     

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

     

Структуры особенно полезны для небольших структур данных, которые имеют   семантика значения. Комплексные числа, точки в системе координат или   Все пары ключ-значение в словаре являются хорошими примерами структур.   использование структур, а не классов для небольших структур данных может сделать   большая разница в количестве выделенных памяти приложения   выполняет. Например, следующая программа создает и инициализирует   массив из 100 точек. С Точкой, реализованной как класс, 101   создаются отдельные объекты - по одному для массива и по одному для каждого   100 элементов.

 
class Point
{
   public int x, y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }
}

class Test
{
   static void Main() {
      Point[] points = new Point[100];
      for (int i = 0; i < 100; i++) points[i] = new Point(i, i);
   }
}

Альтернатива - сделать Point структурой.

 
struct Point
{
   public int x, y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }
}

Теперь создается только один объект - один для массива - и экземпляры Point хранятся в виде строки в массиве.

Конструкторы Struct вызываются оператором new, но это не означает, что память выделяется. Вместо того, чтобы динамически размещать объект и возвращать ссылку на него, конструктор структуры просто возвращает само значение структуры (обычно во временном месте в стеке), и это значение затем копируется по мере необходимости.

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

 
Point a = new Point(10, 10);
Point b = a;
a.x = 20;
Console.WriteLine(b.x);

Если Point - это класс, выходное значение равно 20, поскольку a и b ссылаются на один и тот же объект. Если Point является структурой, выходное значение равно 10, поскольку при присваивании a-b создается копия значения, и на эту копию не влияет последующее присвоение a.x.

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

    
39
2012-09-17 15: 42: 08Z
  1. Хотя тот факт, что ссылки на структуры не могут быть сохранены, иногда является ограничением, он также является очень полезной характеристикой. Одним из основных недостатков .net является то, что не существует достойного способа передать внешнему коду ссылку на изменяемый объект без потери контроля над этим объектом. Напротив, можно безопасно дать внешнему методу ref изменяемой структуре и знать, что любые мутации, которые внешний метод выполнит с ним, будут выполнены до его возврата. Это очень плохо. NET делатьне имеет понятия о временных параметрах и возвращаемых значениях функций, поскольку ...
    2012-09-17 23: 16: 23Z
  2. ... который позволил бы достичь преимущественной семантики структур, переданных ref, с объектами класса. По сути, локальные переменные, параметры и возвращаемые значения функций могут быть постоянными (по умолчанию), возвратными или эфемерными. Код будет запрещено копировать эфемерные вещи во что-либо, что переживет нынешнюю сферу. Возвращаемые вещи будут похожи на эфемерные, за исключением того, что они могут быть возвращены из функции. Возвращаемое значение функции будет связано с самыми жесткими ограничениями, применимыми к любому из его «возвращаемых» параметров.
    2012-09-17 23: 20: 18Z

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

    
33
2009-02-06 17: 58: 07Z
  1. Да, но большие структуры могут быть более дорогими, чем ссылки на классы (при передаче в методы).
    2013-07-10 11: 55: 56Z

Вот основное правило.

  • Если все поля-члены являются типами значений, создайте struct .

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

Exmaples

 
public struct MyPoint 
{
    public int X; // Value Type
    public int Y; // Value Type
}

public class MyPointWithName 
{
    public int X; // Value Type
    public int Y; // Value Type
    public string Name; // Reference Type
}
    
25
2014-01-22 10: 17: 43Z
  1. Неизменяемые ссылочные типы, такие как string, семантически эквивалентны значениям, и сохранение ссылки на неизменяемый объект в поле не влечет за собой выделения кучи. Разница между структурой с открытыми открытыми полями и объектом класса с открытыми открытыми полями заключается в том, что с учетом кодовой последовательности var q=p; p.X=4; q.X=5;, p.X будет иметь значение 4, если a - это тип структуры, и 5, если это тип класса. Если кто-то хочет иметь возможность легко изменять члены типа, следует выбрать «класс» или «структуру» в зависимости от того, хочет ли изменение q повлиять на p.
    2014-01-22 17: 04: 33Z
  2. Да, я согласен, что ссылочная переменная будет в стеке, но объект, на который она ссылается, будет существовать в куче. Хотя структуры и классы ведут себя по-разному, когда присваиваются другой переменной, но я не думаю, что это решающий фактор.
    2014-01-23 05: 33: 13Z
  3. Изменяемые структуры и изменяемые классы ведут себя совершенно по-разному; если один прав, другой скорее всего будет неправ. Я не уверен, что поведение не будет решающим фактором при определении, использовать ли структуру или класс.
    2014-01-23 13: 34: 07Z
  4. Я сказал, что это не является решающим фактором, потому что часто, когда вы создаете класс или структуру, вы не уверены, как она будет использоваться. Таким образом, вы концентрируетесь на том, как вещи имеют смысл с точки зрения дизайна. В любом случае, я никогда не видел ни одного места в библиотеке .NET, где структура содержит ссылочную переменную.
    2014-01-24 02: 01: 43Z
  5. Тип структуры ArraySegment<T> инкапсулирует T[], который всегда является типом класса. Тип конструкции KeyValuePair<TKey,TValue>часто используется с типами классов в качестве общих параметров.
    2014-01-25 17: 32: 40Z

Во-первых: взаимодействие сценариев или когда вам нужно указать расположение памяти

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

    
18
2009-02-06 18: 12: 58Z

Вам необходимо использовать "struct" в ситуациях, когда вы хотите явно указать макет памяти, используя StructLayoutAttribute - обычно для PInvoke.

Редактировать: Комментарий указывает, что вы можете использовать класс или структуру со StructLayoutAttribute, и это, безусловно, верно. На практике вы обычно используете struct - она ​​распределяется в стеке, а не в куче, что имеет смысл, если вы просто передаете аргумент в вызов неуправляемого метода.

    
17
2009-02-06 18: 41: 35Z
  1. StructLayoutAttribute может применяться к структурам или классам, поэтому это не является причиной для использования структур.
    2009-02-06 18: 32: 07Z
  2. Почему имеет смысл, если вы просто передаете аргумент в вызов неуправляемого метода?
    2017-11-21 00: 41: 09Z

Я использую структуры для упаковки или распаковки любого двоичного формата связи. Это включает чтение или запись на диск, списки вершин DirectX, сетевые протоколы или работу с зашифрованными /сжатыми данными.

Три перечисленных вами руководства не были полезны для меня в этом контексте. Когда мне нужно выписать четыреста байтов материала в определенном порядке, я определю структуру размером четыреста байтов и заполню ее любыми несвязанными значениями, которые она должна иметь, и я собираюсь установить его любым способом, который имеет больше всего смысла в то время. (Хорошо, четыреста байтов было бы довольно странно - но когда я писал для жизни файлы Excel, я имел дело со структурами размером до сорока байтов всего, потому что это то, насколько велики некоторые записи BIFF.) р>     

16
2009-02-06 18: 25: 49Z
  1. Не могли бы вы так же легко использовать ссылочный тип для этого?
    2017-11-21 00: 39: 47Z

За исключением типов значений, которые используются непосредственно средой выполнения и различными другими для целей PInvoke, значения типов типов следует использовать только в 2 сценариях.

  1. Когда вам нужно копировать семантику.
  2. Когда вам нужна автоматическая инициализация, обычно в массивах этих типов.
15
2009-02-06 18: 15: 06Z
  1. # 2, по-видимому, является частью причины преобладания структуры в классах коллекций .Net.
    2011-08-07 11: 38: 50Z
  2. Если первое, что нужно сделать при создании хранилища типа класса, это создать новый экземпляр этого типа, сохранить ссылку на него в этом месте и никогда не копировать ссылку в другом месте и не перезаписывать ее, а затемкт и класс будут вести себя одинаково. Структуры имеют удобный стандартный способ копирования всех полей из одного экземпляра в другой и, как правило, обеспечивают более высокую производительность в тех случаях, когда никогда не будет дублироваться ссылка на класс (за исключением эфемерного параметра this, используемого для вызова его методов); классы позволяют дублировать ссылки.
    2013-08-28 20: 02: 09Z

.NET поддерживает value types и reference types (в Java вы можете определять только ссылочные типы). Экземпляры reference types распределяются в управляемой куче и удаляются, когда на них нет невыполненных ссылок. Экземпляры value types, с другой стороны, выделяются в stack, и, следовательно, выделенная память восстанавливается, как только заканчивается их область действия. И, конечно, value types передаются по значению, а reference types по ссылке. Все примитивные типы данных C #, за исключением System.String, являются типами значений.

Когда использовать структуру над классом,

В C # structs - это value types, классы - reference types. Вы можете создавать типы значений в C #, используя ключевое слово enum и ключевое слово struct. Использование value type вместо reference type приведет к уменьшению количества объектов в управляемой куче, что приведет к меньшей нагрузке на сборщик мусора (GC), менее частым циклам GC и, следовательно, к повышению производительности. Однако у value types есть и свои минусы. Обход большого struct определенно обходится дороже, чем передача справки, это одна очевидная проблема. Другая проблема - это накладные расходы, связанные с boxing/unboxing. Если вам интересно, что означает boxing/unboxing, перейдите по этим ссылкам для хорошего объяснения boxing и unboxing. Помимо производительности, бывают случаи, когда вам просто нужно, чтобы типы имели семантику значений, что было бы очень сложно (или некрасиво) реализовать, если бы reference types был всем, что у вас есть. Вы должны использовать только value types, когда вам нужна семантика копирования или требуется автоматическая инициализация, обычно в arrays из этих типов.

    
14
2012-09-17 11: 21: 43Z
  1. Копирование небольших структур или передача по значению так же дешевы, как копирование или передача ссылки на класс или передача структур на ref. Передача структуры любого размера на ref стоит столько же, сколько передача ссылки на класс по значению. Копирование структуры любого размера или передача по значению дешевле, чем выполнение защитной копии объекта класса и сохранение или передача ссылки на него. Классы больших времен лучше, чем структуры для хранения значений: (1) когда классы неизменны (чтобы избежать защитного копирования), и каждый созданный экземпляр будет много передаваться, или ...
    2012-09-17 15: 04: 12Z
  2. ... (2) когда по разным причинам структура просто не может быть использована [например, потому что нужно использовать вложенные ссылки для чего-то вроде дерева или потому что нужен полиморфизм]. Обратите внимание, что при использовании типов значений, как правило, следует открывать поля, напрямую отсутствующие по определенной причине (в то время как в большинстве типов классов поля должны быть заключены в свойства). Многие из так называемых «зол» изменчивых типов значений происходят из-за ненужного переноса полей в свойствах (например, в то время как некоторые компиляторы позволяют вызывать установщик свойств в структуре только для чтения, потому что иногда это происходит ...
    2012-09-17 15: 10: 38Z
  3. ... поступайте правильно, все компиляторы будут правильно отклонять попытки напрямую устанавливать поля в таких структурах; лучший способ обеспечить отклонение компиляторами readOnlyStruct.someMember = 5; - это не делать свойство someMember доступным только для чтения, а вместо этого делать его полем.
    2012-09-17 15: 15: 08Z

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

Обратите внимание, что можно спроектировать тип структуры так, чтобы он по существу вел себя как тип класса, если структура содержит частное поле типа класса и перенаправляет своих собственных членов на объект обернутого класса. Например, PersonCollection может предлагать свойства SortedByName и SortedById, которые содержат «неизменяемую» ссылку на PersonCollection (установленную в их конструкторе) и реализуют GetEnumerator, вызывая либо creator.GetNameSortedEnumerator, либо creator.GetIdSortedEnumerator. Такие структуры будут вести себя как ссылка на PersonCollection, за исключением того, что их методы GetEnumerator будут связаны с различными методами в PersonCollection. Можно также иметь структуру для переноса части массива (например, можно определить структуру ArrayRange<T>, которая будет содержать T[] с именем Arr, int Offset и int Length, с индексированным свойством, которое для индекса idx в диапазоне От 0 до Length-1, доступ к Arr[idx+Offset]). К сожалению, если foo является экземпляром такой структуры, доступным только для чтения, текущие версии компилятора не будут разрешать такие операции, как foo[3]+=4;, потому что у них нет способа определить, будут ли такие операции пытаться записать в поля foo.

Также возможно спроектировать структуру, которая будет вести себя как тип значения, который содержит коллекцию переменного размера (которая будет копироваться всякий раз, когда есть структура), но единственный способ сделать это - убедиться, что никакой объект на которую структура содержит ссылку, будет когда-либо подвергаться чему-либо, что может ее изменить. Например, можно иметь массивоподобную структуру, которая содержит закрытый массив, и чей индексированный метод «put» создает новый массив, содержимое которого аналогично содержимому оригинала, за исключением одного измененного элемента. К сожалению, может быть довольно сложно заставить такие структуры работать эффективно. Хотя бывают случаи, когда семантика структуры может быть удобной (например, возможность передавать массивоподобную коллекцию в подпрограмму, когда вызывающая сторона и вызываемая сторона знают, что внешний код не будет изменять коллекцию, это может быть лучше, чем требовать и вызывающую, и требование защищенного копирования любых данных, которые им даны), требование, чтобы ссылки на классы указывали на объекты, которые никогда не будут видоизменяться, часто является довольно серьезным ограничением.

    
10
2012-09-17 15: 23: 18Z

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

 
public struct IntStruct {
    public int Value {get; set;}
}

Исключение следующих результатов приводит к 5 экземплярам структуры, хранящейся в памяти:

 
var struct1 = new IntStruct() { Value = 0 }; // original
var struct2 = struct1;  // A copy is made
var struct3 = struct2;  // A copy is made
var struct4 = struct3;  // A copy is made
var struct5 = struct4;  // A copy is made

// NOTE: A "copy" will occur when you pass a struct into a method parameter.
// To avoid the "copy", use the ref keyword.

// Although structs are designed to use less system resources
// than classes.  If used incorrectly, they could use significantly more.

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

 
public class IntClass {
    public int Value {get; set;}
}

Исключение следующих результатов приводит к только одному экземпляру объекта класса в памяти.

 
var class1 = new IntClass() { Value = 0 };
var class2 = class1;  // A reference is made to class1
var class3 = class2;  // A reference is made to class1
var class4 = class3;  // A reference is made to class1
var class5 = class4;  // A reference is made to class1  

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

 
var struct1 = new IntStruct() { Value = 0 };
var struct2 = struct1;
struct2.Value = 1;
// At this point, a developer may be surprised when 
// struct1.Value is 0 and not 1
    
10
2017-07-20 18: 36: 18Z

Я сделал небольшой тест с BenchmarkDotNet , чтобы лучше понять преимущества "struct" в числах , Я тестирую циклический просмотр массива (или списка) структур (или классов). Создание этих массивов или списков выходит за рамки теста - ясно, что более тяжелый «класс» будет использовать больше памяти и будет включать GC.

Итак, вывод таков: будьте осторожны с LINQ и скрытыми структурами, бокс /распаковка и использование структур для микрооптимизации строго остаются с массивами.

P.S. Еще один тест для прохождения struct /class через стек вызовов находится здесь https://stackoverflow.com/a/47864451/506147  

BenchmarkDotNet=v0.10.8, OS=Windows 10 Redstone 2 (10.0.15063)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233542 Hz, Resolution=309.2584 ns, Timer=TSC
  [Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2101.1
  Clr    : Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2101.1
  Core   : .NET Core 4.6.25211.01, 64bit RyuJIT


          Method |  Job | Runtime |      Mean |     Error |    StdDev |       Min |       Max |    Median | Rank |  Gen 0 | Allocated |
---------------- |----- |-------- |----------:|----------:|----------:|----------:|----------:|----------:|-----:|-------:|----------:|
   TestListClass |  Clr |     Clr |  5.599 us | 0.0408 us | 0.0382 us |  5.561 us |  5.689 us |  5.583 us |    3 |      - |       0 B |
  TestArrayClass |  Clr |     Clr |  2.024 us | 0.0102 us | 0.0096 us |  2.011 us |  2.043 us |  2.022 us |    2 |      - |       0 B |
  TestListStruct |  Clr |     Clr |  8.427 us | 0.1983 us | 0.2204 us |  8.101 us |  9.007 us |  8.374 us |    5 |      - |       0 B |
 TestArrayStruct |  Clr |     Clr |  1.539 us | 0.0295 us | 0.0276 us |  1.502 us |  1.577 us |  1.537 us |    1 |      - |       0 B |
   TestLinqClass |  Clr |     Clr | 13.117 us | 0.1007 us | 0.0892 us | 13.007 us | 13.301 us | 13.089 us |    7 | 0.0153 |      80 B |
  TestLinqStruct |  Clr |     Clr | 28.676 us | 0.1837 us | 0.1534 us | 28.441 us | 28.957 us | 28.660 us |    9 |      - |      96 B |
   TestListClass | Core |    Core |  5.747 us | 0.1147 us | 0.1275 us |  5.567 us |  5.945 us |  5.756 us |    4 |      - |       0 B |
  TestArrayClass | Core |    Core |  2.023 us | 0.0299 us | 0.0279 us |  1.990 us |  2.069 us |  2.013 us |    2 |      - |       0 B |
  TestListStruct | Core |    Core |  8.753 us | 0.1659 us | 0.1910 us |  8.498 us |  9.110 us |  8.670 us |    6 |      - |       0 B |
 TestArrayStruct | Core |    Core |  1.552 us | 0.0307 us | 0.0377 us |  1.496 us |  1.618 us |  1.552 us |    1 |      - |       0 B |
   TestLinqClass | Core |    Core | 14.286 us | 0.2430 us | 0.2273 us | 13.956 us | 14.678 us | 14.313 us |    8 | 0.0153 |      72 B |
  TestLinqStruct | Core |    Core | 30.121 us | 0.5941 us | 0.5835 us | 28.928 us | 30.909 us | 30.153 us |   10 |      - |      88 B |

код:

 
[RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
    [ClrJob, CoreJob]
    [HtmlExporter, MarkdownExporter]
    [MemoryDiagnoser]
    public class BenchmarkRef
    {
        public class C1
        {
            public string Text1;
            public string Text2;
            public string Text3;
        }

        public struct S1
        {
            public string Text1;
            public string Text2;
            public string Text3;
        }

        List<C1> testListClass = new List<C1>();
        List<S1> testListStruct = new List<S1>();
        C1[] testArrayClass;
        S1[] testArrayStruct;
        public BenchmarkRef()
        {
            for(int i=0;i<1000;i++)
            {
                testListClass.Add(new C1  { Text1= i.ToString(), Text2=null, Text3= i.ToString() });
                testListStruct.Add(new S1 { Text1 = i.ToString(), Text2 = null, Text3 = i.ToString() });
            }
            testArrayClass = testListClass.ToArray();
            testArrayStruct = testListStruct.ToArray();
        }

        [Benchmark]
        public int TestListClass()
        {
            var x = 0;
            foreach(var i in testListClass)
            {
                x += i.Text1.Length + i.Text3.Length;
            }
            return x;
        }

        [Benchmark]
        public int TestArrayClass()
        {
            var x = 0;
            foreach (var i in testArrayClass)
            {
                x += i.Text1.Length + i.Text3.Length;
            }
            return x;
        }

        [Benchmark]
        public int TestListStruct()
        {
            var x = 0;
            foreach (var i in testListStruct)
            {
                x += i.Text1.Length + i.Text3.Length;
            }
            return x;
        }

        [Benchmark]
        public int TestArrayStruct()
        {
            var x = 0;
            foreach (var i in testArrayStruct)
            {
                x += i.Text1.Length + i.Text3.Length;
            }
            return x;
        }

        [Benchmark]
        public int TestLinqClass()
        {
            var x = testListClass.Select(i=> i.Text1.Length + i.Text3.Length).Sum();
            return x;
        }

        [Benchmark]
        public int TestLinqStruct()
        {
            var x = testListStruct.Select(i => i.Text1.Length + i.Text3.Length).Sum();
            return x;
        }
    }
    
10
2018-07-04 20: 42: 45Z
  1. Вы выяснили, почему структуры намного медленнее при использовании в списках и тому подобное? Вы упомянули скрытый бокс и распаковку? Если так, почему это происходит?
    2017-08-12 13: 24: 40Z
  2. Доступ к структуре в массиве должен быть более быстрым просто из-за того, что никаких дополнительных ссылок не требуется. Бокс /Распаковка это случай для linq.
    2017-08-27 12: 26: 44Z

Нет, я не совсем согласен с правилами. Это хорошие рекомендации по производительности и стандартизации, но не в свете возможностей.

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

В этом случае я использую классы для представления объектов реального мира в их более крупной форме, я использую структуры для представления более мелких объектов, которые имеют более точное использование. То, как вы это сказали, «более сплоченное целое». Ключевое слово является связным. Классы будут более объектно-ориентированными элементами, в то время как структуры могут иметь некоторые из этих характеристик, хотя и в меньшем масштабе. ИМО.

Я часто их использую в тегах Treeview и Listview, где очень быстро можно получить доступ к общим статическим атрибутам. Я всегда изо всех сил пытался получить эту информацию другим способом. Например, в моих приложениях базы данных я использую Treeview, где у меня есть таблицы, SP, функции или любые другие объекты. Я создаю и заполняю свою структуру, помещаю ее в тег, извлекаю, получаю данные выбора и так далее. Я бы не стал делать это с классом!

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

    
9
2018-12-01 19: 37: 20Z
  1. Структуры могут быть разумно использованы для представления легких неизменяемых объектов, или они могут быть разумно использованы для представления фиксированных наборов связанных, но независимых переменных (например, координат точки). ). Рекомендации на этой странице хороши для структур, которые предназначены для использования в первой цели, но не подходят для структур, которые предназначены для выполнения второй цели. В настоящее время я думаю, что структуры, которые имеют какие-либо частные поля, должны, как правило, соответствовать указанному описанию, но многие структуры должны раскрывать все свое состояние через открытые поля.
    2013-07-25 16: 04: 53Z
  2. Если спецификация для типа "3d point" указывает, что все его состояние предоставляется через читаемые элементы x, y и z, и возможно создать экземпляр с любая комбинация double значений для этих координат, такая спецификация вынуждает ее вести себя семантически идентично структуре с открытым полем, за исключением некоторых деталей многопоточного поведения (в некоторых случаях неизменный класс будет лучше, в то время как поле с открытым полем структура будет лучше в других; так называемая «неизменяемая» структура будет хуже в каждом случае).
    2013-07-25 16: 15: 01Z

Мое правило -

1, всегда использовать класс;

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

    
8
2013-08-30 08: 22: 20Z
  1. Существенный вариант использования, который Microsoft игнорирует, - это когда требуется переменная типа Foo дляpsulate фиксированный набор независимых значений (например, координаты точки), которые иногда нужно передавать как группа, а иногда хотят изменить независимо. Я не нашел ни одного шаблона для использования классов, который сочетал бы обе цели почти так же хорошо, как простая структура с открытыми полями (которая, будучи фиксированной коллекцией независимых переменных, идеально подходит для этой цели).
    2013-08-30 17: 10: 37Z
  2. @ supercat: я думаю, что не совсем справедливо обвинять в этом Microsoft. Реальная проблема здесь заключается в том, что C # как объектно-ориентированный язык просто не фокусируется на простых типах записей, которые только представляют данные без особого поведения. C # не является языком мультипарадигмы в той же степени, что, например, С ++ есть. При этом, я также считаю, что очень немногие программируют чистый ООП, поэтому, возможно, C # - слишком идеалистический язык. (Например, я недавно начал выставлять public readonly полей в моих типах, потому что создание свойств только для чтения - это просто слишком много работы, практически бесполезной.)
    2013-08-31 09: 22: 00Z
  3. @ stakx: ему не нужно "фокусироваться" на таких типах; достаточно признать их такими, какие они есть. Самым большим недостатком C # в отношении структур является его самая большая проблема и во многих других областях: язык предоставляет неадекватные средства для указания того, когда определенные преобразования подходят или не подходят, а отсутствие таких средств приводит к неудачным проектным решениям. Например, 99% «изменяемых структур являются злыми» происходит от превращения компилятором MyListOfPoint[3].Offset(2,3); в var temp=MyListOfPoint[3]; temp.Offset(2,3);, преобразование, которое является поддельным при применении ...
    2013-08-31 22: 44: 03Z
  4. ... для метода Offset. Правильный способ предотвращения такого поддельного кода не должен состоять в том, чтобы сделать структуры без необходимости неизменными, а вместо этого позволить тегам типа Offset помечать атрибутом, запрещающим вышеупомянутое преобразование. Неявные числовые преобразования тоже могли бы быть намного лучше, если бы их можно было пометить так, чтобы они были применимы только в тех случаях, когда их вызов был бы очевиден. Если существуют перегрузки для foo(float,float) и foo(double,double), я бы сказал, что попытка использовать float и double часто не должна приводить к неявному преобразованию, а вместо этого должна быть ошибкой.
    2013-08-31 22: 50: 03Z
  5. Прямое присвоение значения double для float или передача его методу, который может принимать аргумент float, но не double, почти всегда делает то, что задумал программист , Напротив, присвоение выражения float номеру double без явного преобразования типа часто является ошибкой. Единственное время, позволяющее неявное преобразование double->float, может вызвать проблемы, - это когда будет выбрана не идеальная перегрузка. Я бы сказал, что правильный способ предотвратить это не должен был запрещать implcit double -> float, но помечать перегрузки атрибутами, чтобы запретить преобразование.
    2013-08-31 23: 00: 25Z

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

Классы и структуры (Руководство по программированию в C #)

    
8
2014-05-23 09: 52: 52Z
  1. Структуры также очень хороши в тех случаях, когда необходимо скрепить несколько связанных, но независимых переменных вместе с клейкой лентой (например, координаты точки). Рекомендации MSDN разумны, если кто-то пытается создать структуры, которые ведут себя как объекты, но гораздо менее уместны при проектировании агрегатов; некоторые из них почти точно не так в последней ситуации. Например, чем выше степень независимости переменных, инкапсулированных в тип, тем больше преимущество использования структуры с открытым полем, а не неизменяемого класса.
    2014-05-27 17: 39: 40Z

Я имел дело с именованным каналом Windows Communication Foundation [WCF] и заметил, что имеет смысл использовать Structs, чтобы обеспечить обмен данными типом значения вместо тип ссылки .

    
5
2017-04-27 15: 54: 04Z
  1. Это лучшая подсказка из всех, ИМХО.
    2017-03-12 17: 05: 11Z

Я думаю, что хорошее первое приближение - "никогда".

Я думаю, что хорошее второе приближение - "никогда".

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

    
4
2009-02-06 17: 44: 34Z
  1. Я бы не согласился с этим ответом. Структуры имеют законное использование во многих сценариях. Вот пример - маршалинг перекрестных процессов данных атомарным способом.
    2009-02-06 17: 54: 57Z
  2. Вы должны отредактировать свой пост и уточнить свои пункты - вы уже высказали свое мнение, но вы должны подтвердить это тем, почему вы придерживаетесь этого мнения.
    2009-02-06 20: 43: 09Z
  3. Я думаю, что им нужен эквивалент чиповой карты Totin '( en.wikipedia.org/wiki/Totin%27_Chip ) для использования структур. Серьезно.
    2010-05-13 19: 00: 21Z
  4. Как 87.5K человек публикует такой ответ? Он делал это, когда был ребенком?
    2015-06-02 10: 34: 22Z
  5. @ Рохит - это было шесть лет назад; Стандарты сайта были очень разные тогда. это все еще плохой ответ, но вы правы.
    2015-06-02 14: 36: 24Z

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

Итак, вы должны использовать структуры, когда хотите представить более простые структуры данных, особенно если вы знаете, что будете создавать их экземпляры. Есть много электроннойПримеры в .NET Framework, где Microsoft использовала структуры вместо классов, например, структуру Point, Rectangle и Color.

    
4
2017-10-24 13: 15: 22Z

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

http://00sharp.wordpress.com /2013/07/03 /а-футляр-для-структура /

    
3
2013-07-03 14: 20: 39Z

Типы структуры или значения могут использоваться в следующих сценариях -

  1. Если вы хотите запретить сбор объекта при сборке мусора.
  2. Если это простой тип и ни одна функция-член не изменяет свои поля экземпляра
  3. Если нет необходимости наследовать от других типов или от других типов.

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

    
3
2015-08-31 08: 50: 01Z

Вкратце, используйте struct if:

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

2- свойства и поля в вашем объекте являются типом значения, и они не так велики.

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

    
3
2016-05-26 14: 31: 11Z

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

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

    
2
2012-03-02 18: 28: 29Z

МИФ № 1. СТРУКТЫ - ЛЕГКИЙ КЛАСС

Этот миф бывает разных форм. Некоторые люди считают, что типы значений не могут или не должно иметь методов или другого значимого поведения - их следует использовать как простые типы передачи данных, только с открытыми полями или простыми свойствами. Тип DateTime является хороший контрпример к этому: имеет смысл для него быть типом значения, с точки зрения фундаментальная единица, такая как число или символ, и также имеет смысл для него быть способен выполнять расчеты на основе его стоимости. Глядя на вещи с другой направление, типы передачи данных часто должны быть ссылочными типами в любом случае - решение должны основываться на желаемом значении или семантике ссылочного типа, а не на простоте тип.  Другие люди считают, что типы значений «легче», чем ссылочные типы в терминах производительности. Правда в том, что в некоторых случаях типы значений более производительны - им не требуется сборка мусора, если они не упакованы, не имеют тип накладные расходы на идентификацию и не требуют разыменования, например. Но в других пути, ссылочные типы более производительны - передача параметров, присвоение значений Переменные, возвращаемые значения и подобные операции требуют только 4 или 8 байтов для копирования (в зависимости от того, используете ли вы 32-разрядную или 64-разрядную версию CLR), а не копирование всех данных. Представьте, если бы ArrayList был каким-то «чистым» значениеми тип, и Передача выражения ArrayList методу, включающему копирование всех его данных! Почти во всех случаях производительность не зависит от такого рода решений. Узкие места почти никогда не бывают такими, какими вы их считаете, и прежде чем принимать проектное решение, основанное на производительности, вы должны измерить различные варианты.  Стоит отметить, что сочетание двух убеждений тоже не работает. Это не имеет значения, сколько методов имеет тип (будь то класс или структура) - память, взятая за экземпляр, не затрагивается. (Там есть стоимость с точки зрения памяти взялся за сам код, но это происходит один раз, а не для каждого экземпляра.)

МИФ № 2: СПРАВОЧНЫЕ ТИПЫ ЖИТЬ НА КАРТЕ; ЦЕННЫЕ ЗНАКИ ЖИТЬ НА СТЕКЕ

Это часто вызвано ленью повторяющего его человека. Первый часть верна - экземпляр ссылочного типа всегда создается в куче. Это Вторая часть, которая вызывает проблемы. Как я уже отмечал, значение переменной живет везде, где она объявлена, поэтому, если у вас есть класс с переменной экземпляра типа int, значение этой переменной для любого данного объекта всегда будет там, где остальные данные для объекта это в куче. Только локальные переменные (переменные, объявленные в методах) и метод параметры живут в стеке. В C # 2 и более поздних версиях даже некоторые локальные переменные жить в стеке, как вы увидите, когда мы рассмотрим анонимные методы в главе 5. СООТВЕТСТВУЮТ ЛИ ЭТИ КОНЦЕПЦИИ СЕЙЧАС? Можно утверждать, что если вы пишете управляемый код, вы должны позволить среде выполнения беспокоиться о том, как лучше всего использовать память. Действительно, спецификация языка не дает никаких гарантий о том, что живет где; будущая среда выполнения может создать несколько объектов в стеке, если знает, что это может сойти с рук, или компилятор C # может генерировать код, который вряд ли использует стек вообще. Следующий миф обычно является просто вопросом терминологии.

МИФ № 3: ОБЪЕКТЫ ПРОХОДЯТ ПО ССЫЛКЕ В C # ПО УМОЛЧАНИЮ

Это, наверное, самый распространенный миф. Опять же, люди, которые делают это утверждают, часто (хотя и не всегда) знают, как на самом деле ведет себя C #, но они не знают что на самом деле означает «передать по ссылке». К сожалению, это сбивает с толку людей, которые знаю, что это значит.  Формальное определение передачи по ссылке относительно сложное, включающее l-значения и подобная компьютерная терминология, но важно то, что если вы передадите Переменная по ссылке, метод, который вы вызываете, может изменить значение переменной вызывающей стороны, изменив значение ее параметра. Теперь помните, что значение ссылки Переменная типа - это ссылка, а не сам объект. Вы можете изменить содержимое объект, на который ссылается параметр без передачи самого параметра по ссылке. Например, следующий метод изменяет содержимое StringBuilder объект, о котором идет речь, но выражение вызывающего все равно будет ссылаться на тот же объект, что и раньше:

 
void AppendHello(StringBuilder builder)
{
    builder.Append("hello");
}

При вызове этого метода значение параметра (ссылка на StringBuilder) передается по значению. Если бы вы изменили значение переменной построителя в метод - например, с помощью оператора builder = null; - это изменение не будет видел вызывающий, вопреки мифу.  Интересно отметить, что не только бит «по ссылке» мифа неточен, но и бит «объекты переданы». Сами объекты никогда не передаются, либо по ссылке или по значению. Когда задействован ссылочный тип, либо переменная передается по ссылке или значение аргумента (ссылка) передается по значению. Помимо всего прочего, это отвечает на вопрос, что происходит, когда ноль используется в качестве аргумента по значению - если объекты передаются, это приведет к проблемы, так как не было бы объекта для передачи! Вместо этого нулевая ссылка передается значение так же, как и любая другая ссылка.  Если это быстрое объяснение оставило вас в замешательстве, вы можете посмотреть мою статью «Передача параметров в C #» ( http: //mng.bz/otVt ), в который входит гораздо больше подробно.  Эти мифы не единственные вокруг. Бокс и распаковка приходят за своими справедливая доля недоразумений, которые я постараюсь прояснить в следующем.

Ссылка: C # в 3-м выпуске Depth, автор Jon Skeet

    
1
2019-02-27 16: 39: 27Z

Структуры во многом похожи на классы /объекты. Структура может содержать функции, члены и могут быть унаследованы. Но структуры в C # используются только для хранения данных . Структуры занимают меньше ОЗУ , чем классы, и сборщику мусора легче . Но когда вы используете функции в своей структуре, компилятор на самом деле воспринимает эту структуру очень похоже на класс /объект, поэтому, если вам нужно что-то с функциями, используйте класс /объект .

    
- 11
2014-11-20 20: 02: 07Z
  1. Структуры НЕ могут быть унаследованы, см. msdn.microsoft.com/en-us/library/0taef578.aspx
    2015-09-10 14: 45: 41Z
источник размещен Вот