Слепо конвертировать структуры в классы, чтобы скрыть конструктор по умолчанию?

StackOverflow https://stackoverflow.com/questions/1429495

Вопрос

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

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

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

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

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

Неужели все просто конвертируют свои structs для classes в этой ситуации, не задумываясь?

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

<Ол>
  • Создайте свойство, подобное IsValid, чтобы указать, является ли оно допустимой структурой, как вы указываете и
  • в .Net 2.0 рассмотрите возможность использования Nullable < T > разрешить неинициализированную (нулевую) структуру.
  • Изменение структуры на класс может иметь некоторые очень тонкие последствия (с точки зрения использования памяти и идентичности объектов, которые чаще возникают в многопоточной среде), а также не столь тонкие, но сложные для отладки исключения NullReferenceExceptions для неинициализированных объектов.

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

    new MyStruct[1000];
    

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

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

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

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

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

    • Добавьте в структуру свойство Am-I-Initialized (например, HasValue на Nullable).
    • Разрешить обнуляемой структуре быть допустимым значением (например, 0 является допустимым значением для десятичной дроби).
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top