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

Имеет ли смысл определять структуру с элементом ссылочного типа?

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

public struct SomeStruct
{
    string name;
    Int32  place;
}

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

Я прав? Может кто-нибудь объяснить это?

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

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

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

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