Имеет ли смысл определять структуру с помощью элемента ссылочного типа? - PullRequest
19 голосов
/ 11 апреля 2011

Есть ли смысл определять структуру с помощью элемента ссылочного типа (а не определять ее как класс)?Например, чтобы определить эту структуру:

public struct SomeStruct
{
    string name;
    Int32  place;
}

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

Ответы [ 4 ]

20 голосов
/ 11 апреля 2011

В девяти случаях из десяти вы должны создавать класс, а не структуру. Структуры и классы имеют очень разную семантику в C # по сравнению с тем, что вы можете найти в C ++ дляпример.Большинство программистов, которые используют структуру , должны использовать класс, что делает такие вопросы совершенно откровенно неуместными.

Вот несколько быстрых правил о том, когда следует выбирать структуру над классом:

  1. Никогда.
    ... О, ты еще читаешь?Вы настойчивыХорошо, хорошо.
  2. Когда у вас есть явная потребность в семантике типа значения, в отличие от семантики ссылочного типа.
  3. Когда у вас очень маленький тип (Основное правило - это объем памяти, не превышающий 16 байт.)
  4. Когда объекты, представленные вашей структурой, будут недолговечными и неизменными (не изменится).
  5. И иногда, для целей взаимодействия с собственным кодом, который использует структуры.

Но если вы приняли информированное решение и действительно уверены, что вы делаете на самом деле нужна структура, а не класс, вам нужно вернуться к пункту 2 и понять, что такое семантика типов значений. Статья Джона Скита здесь должна пройти долгий путь к разъяснению различия.

После того, как вы это сделаете, вы должны понять, почему определение ссылочного типа внутри типа значения (структуры)не проблема.Типы ссылок похожи на указатели.Поле внутри структуры не хранит фактический тип;скорее он хранит указатель (или ссылку) на этот тип.Нет ничего противоречивого или неправильного в объявлении структуры с полем, содержащим ссылочный тип.Он не будет ни «замедлять объект», ни «вызывать GC», то есть две проблемы, которые вы выражаете в комментарии.

3 голосов
/ 11 апреля 2011

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

2 голосов
/ 01 ноября 2012

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

  1. Все экземпляры этого типа могут рассматриваться как неотъемлемые по своей природе.(как в случае с `string`)
  2. Семантика структуры ясно подразумевает, что поле идентифицирует объект, к которому оно относится, а не инкапсулирует его состояние, и что состояние объектаупомянутое поле не считается частью структуры.Например, в KeyValuePairможно было бы ожидать, что `Value 'идентифицирует экземпляр формы;перемещение формы по экрану изменит `Value.Bounds`, но не будет считаться изменением` Value` (которое будет продолжать ссылаться на ту же форму, независимо от ее расположения на экране)

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

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

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

2 голосов
/ 11 апреля 2011

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

...