2012-03-29 1 views
2

Можно ли применять правила или выдавать ошибку при использовании инициализаторов объектов в C#? Я хотел бы бросить ошибку компилятора или предупреждение, если объект инициализирован, но отсутствует определенное свойство.Ошибка инициализации объекта инициализатора

public class Party 
{ 
    public string Name { get; set; } 
    public string Date { get; set; } 
    public Location Location { get; set; } 
} 

public class SignUpForParty 
{ 
    public void DoSomething() 
    { 
     Party party = new Party() 
     { 
      Name = "New Years Party!", 
      Date = "Dec 31, 1999" 
      // Show WARNING/ERROR here because no Location given 
     }; 
    } 
} 

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

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

Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty 
+1

Вы можете поместить каждый параметр конструктора в свою линию, и это будет выглядеть очень похоже. Вы упомянули перегрузку конструктора, но вы также сказали, что хотите установить * all * properties set, который предлагает один uber-конструктор. – dlev

+0

Спасибо за ответы. Я запутываю инициаторов объектов с конструкторами. Я хотел получить лучшее из обоих миров - создание объекта с принудительным исполнением, но с легким стилем инициаторов объектов. Я не хотел, чтобы кучка конструкторов uber. То, что происходит с @ reed-copsey, также верно в моем сценарии, поскольку то, что требуется, должно быть в конструкторе, и для инициаторов следует оставить необязательный материал. – daviddeath

ответ

4

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

Инициализаторы объектов действительно не должны рассматриваться как альтернативы написанию конструктора.

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

Инициализаторы объектов полезны для дополнительных объектов, но не следует полагаться на требования вашего типа.

3

Вы не можете принудительно инициализировать каждое свойство инициализатором объекта.

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

Если вы идете по этому маршруту, взгляните на интерфейс IDataErrorInfo.

2

Если ваш тип недействителен, когда задано только 2 свойства, вам необходимо исправить свою конструкцию, а не испускать ошибку.

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

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

Кроме того, если PropertyA зависит от PropertyB затем либо

А) Только один из них должен иметь сеттера или

В) Там должно быть логика в инкубаторе каждого правильно инициализировать другой после изменения значения.

Это проблема дизайна, а не проблема языка. Вы не можете заставить синтаксис инициализатора работать иначе, чем его спецификацию.

Obj p = new Obj (1, 2, 3, ... n); // слишком много свойств должно быть довольно

Код не должен быть «хорошеньким», он должен работать. Даже тогда конструктор, который принимает несколько аргументов, является «уродливым»? А? Не покупайте в хипстерскую бессмыслицу, пишите код, который работает и работает хорошо.

+0

Согласен на все вопросы, спасибо. «... вы предоставляете конструктор, который заставляет меня поставлять все три значения». Мой вопрос, вероятно, был бы лучше понят, спросив: «Могу ли я предоставить поведение конструктора с инициализаторами?» Который, я узнал, нет. – daviddeath

0

Единственный способ, которым я мог убедиться в этом, - это если какое-то событие (или эквивалент) было поднято, когда инициализатор объекта был завершен. В настоящее время существует Connect request для чего-то подобного.

К сожалению, я не сделал разрез для .NET 4.5:

Спасибо за ваше предложение.

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

К сожалению, мы не можем добавить больше к выпуску, который мы сейчас строим, поэтому я собираюсь решить, что не будет исправлено для этой версии. Тем не менее, я собираю предложение о нашем списке функций для будущего обсуждения.

Еще раз спасибо!

Мадс Torgersen, C# Язык PM

Может быть, это будет сделать это путь в .NET 5+.

+0

Это очень интересная идея. Во многих отношениях это почти то, что я ищу. – daviddeath

+0

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

0

Что относительно Code Contracts?. Это будет утверждать не только то, что вы присвоили значение, но также можете указать допустимые диапазоны.

Или для проверки во время выполнения только с отладочными сборками вы можете использовать вызовы Debug.Assert(...) для достижения того же, что и выше.