Как вы определяете, какое состояние по умолчанию для производной структуры должно быть в C #? - PullRequest
4 голосов
/ 07 апреля 2009

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

Что я хотел бы знать, так это как настроить значение по умолчанию для структуры, которую мне нужно определить? Скажем, я делаю структуру TaxID, и значение по умолчанию должно быть 999-99-9999 по любой причине. Это уже сделано с другими структурами в .NET, а именно с DateTime. Каждый раз, когда вы объявляете DateTime, значение немедленно устанавливается равным 1 января 01 00:00. Почему устанавливается это значение, а не 0/0/0000 00: 00: 0000 AM? За кулисами должно происходить что-то, что делает значение действительно «разумным» при его «значении по умолчанию», даже с учетом ограничений, наложенных на нас c # в отношении структур.

Ответы [ 5 ]

7 голосов
/ 07 апреля 2009

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

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

Подробнее см. Руководство по проектированию .


Я только что посмотрел этот раздел в руководстве по проектированию, 2-е издание, и у них там есть подробный пример, использующий свойства и нетрадиционные переопределения, чтобы обойти это, также. Основной концепцией было частное сохранение значения таким образом, чтобы 0 было «хорошим значением по умолчанию», и выполняло некоторую форму преобразования в каждом свойстве и переопределении метода (включая ToString). В их случае они использовали положительное целое число в качестве примера и всегда сохраняли curVal-1 в закрытом члене, поэтому значение по умолчанию (0) обрабатывается как значение 1. Они добавляют конструктор с int val и сохраняют значение -1 внутри и т. д.

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

--- Редактировать в ответ на комментарии ---

DateTime, как ваш пример, таков, потому что 0 == 1/1/0001 в полночь. DateTime использует один, ulong для представления тиков от 01.01.0001. Вот почему ( отсюда ):

«Тип значения DateTime представляет даты и время со значениями в диапазоне от 12:00:00 до полуночи, 1 января 0001 года от Anno Domini (Common Era) до 23:59:59 PM, 31 декабря 9999 года нашей эры (CE)»

Это полный спектр улонгов в клещах. «0» в структуре DateTime обрабатывается как 1/1/0001 при преобразовании в строку - значения не 1 + 1 + .... - это один 0.

3 голосов
/ 07 апреля 2009

Каждый раз, когда вы объявляете DateTime, значение немедленно устанавливается равным 1 января 01 00:00. Почему устанавливается это значение, а не 0/0/0000 00: 00: 0000 AM? За кулисами должно происходить что-то, что делает значение действительно «разумным» при его «значении по умолчанию», даже с учетом ограничений, наложенных на нас c # в отношении структур.

Скорее всего, оно неявно инициализирует поле тиков default(int) = 0, а 0 тиков означает DateTime.MinValue, когда вы собираетесь получить значение.

2 голосов
/ 07 апреля 2009

Ничего зловещего не происходит. Внутреннее представление DateTime - это число «тиков» в 100 наносекунд с 12:00:00 1 января 0001 года Анно Домини. Когда DateTime создан, счетчик тиков равен нулю. Если вы посмотрите на DateTime с Ildasm, вы увидите, что это немного сложнее, но вы поняли идею. :)

0 голосов
/ 07 апреля 2009

Просто для полноты:

Типы значений в C # (включая массивы, структуры, перечисления) всегда инициализируются для всех нулей. Типы ссылок также изначально равны нулю, лучше знать как null.

В случае перечислений ноль является значением по умолчанию и всегда является возможным значением, даже если оно не определено в перечислении. Лично я обычно определяю 0 как Нет, Пусто, Неизвестно или что-то подобное:

enum MyEnum { A = 1, B = 2, C = 3 };
// ...
MyEnum value = new MyEnum(); // value has a nameless 0

В случае массивов, если это массив ссылочных типов, все они изначально null (что можно рассматривать как указатель на адрес 0). Если это массив типов значений, все они изначально равны нулю или эквивалентны (см. Другие ответы о DateTime.Ticks и почему «обнуленный» DateTime равен 1/1/0001 в 12:00 утра).

Возвращаясь к структурам: то же самое относится. У них всегда будет конструктор по умолчанию без параметров , и вы не можете избежать этого. Все члены типа значения изначально будут нулевыми (или эквивалентными), а все члены ссылочного типа будут null. Подумайте о значениях типа int, short, decimal, char, DateTime (ahem), TimeSpan, Size, Point, Rectangle, Color, Guid ... все они инициализируются всеми нулями.

0 голосов
/ 07 апреля 2009

Вы не можете объявить конструктор по умолчанию в структуре C #. Вы можете смоделировать это поведение, создав личное поле и написав свойство для возврата значения по умолчанию, если оно равно 1/1/1

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