Слепое преобразование структур в классы, чтобы скрыть конструктор по умолчанию? - PullRequest
7 голосов
/ 16 сентября 2009

Я прочитал все вопросы, связанные с этой темой, и они все объясняют, почему конструктор по умолчанию на struct недоступен в C #, но я пока не нашел ни одного человека, который предлагал бы общий порядок действий при столкновении эта ситуация.

Очевидное решение - просто преобразовать struct в class и разобраться с последствиями.

Есть ли другие варианты сохранить его как struct?

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

Я думал, что если мы собираемся сохранить объект как struct, должен быть введен механизм проверки достоверности состояния (что-то вроде свойства IsValid). Я был встречен с большим сопротивлением, и объяснение «кто бы ни использовал API, не должен использовать конструктор по умолчанию», комментарий, который определенно вызвал у меня удивление. (Примечание: рассматриваемый объект создается «должным образом» с помощью статических фабричных методов, а все остальные конструкторы internal.)

Все ли без раздумий просто конвертируют свои struct в class в этой ситуации?

Редактировать: Я хотел бы увидеть некоторые предложения о том, как сохранить этот тип объекта как struct - рассматриваемый выше объект гораздо лучше подходит как struct, чем как class.

Ответы [ 3 ]

4 голосов
/ 16 сентября 2009

Для struct вы проектируете тип так, чтобы созданный по умолчанию экземпляр (все поля равны нулю) был допустимым состоянием. Вы не [ * не должны ] произвольно использовать struct вместо class без уважительной причины - нет ничего плохого в использовании неизменяемого ссылочного типа.

Мои предложения:

  • Убедитесь, что причина использования struct действительна ([настоящий] профилировщик выявил значительные проблемы с производительностью, вызванные интенсивным выделением очень легкого объекта).
  • Создайте тип так, чтобы созданный экземпляр по умолчанию был действительным.
  • Если дизайн типа продиктован внутренними ограничениями взаимодействия / COM, оберните функциональность и не выставляйте struct вне оболочки (закрытый вложенный тип). Таким образом, вы можете легко документировать и проверять правильное использование требований ограниченного типа.
1 голос
/ 16 сентября 2009

Причина этого заключается в том, что структура (экземпляр System.ValueType) обрабатывается специально CLR: она инициализируется со всеми полями, равными 0 (или по умолчанию). Вам даже не нужно его создавать - просто объявите это. Вот почему требуются конструкторы по умолчанию.

Вы можете обойти это двумя способами:

  1. Создайте свойство, подобное IsValid, чтобы указать, является ли оно допустимой структурой, как вы указали и
  2. в .Net 2.0 рассмотрите возможность использования Nullable для разрешения неинициализированной (нулевой) структуры.

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

0 голосов
/ 16 сентября 2009

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

new MyStruct[1000];

У вас есть 3 варианта здесь

  1. вызов конструктора по умолчанию 1000 раз или
  2. создание поврежденных данных (обратите внимание, что структура может содержать ссылки; если вы не инициализируете или не удалите ссылку, вы потенциально можете получить доступ к произвольной памяти), или
  3. очистить выделенную память нулями (на уровне байтов).

.NET делает то же самое для структур и классов: поля и элементы массива закрываются нулями. Это также обеспечивает более согласованное поведение между структурами и классами и отсутствие небезопасного кода. Это также позволяет .NET Framework не специализировать что-то вроде new byte[1000].

И это конструктор по умолчанию для структур .NET требует и заботится о себе: обнуляет все байты.

Теперь, чтобы справиться с этим, у вас есть несколько вариантов:

  • Добавить свойство Am-I-Initialized в структуру (например, HasValue на Nullable).
  • Разрешить обнуляемой структуре быть допустимым значением (например, 0 является допустимым значением для десятичной дроби).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...