Должен ли я использовать один раз установить переменные?
Это пахнет?
У меня есть несколько свойств, которые вы можете установить только один раз. Они могут быть установлены в любое время в течение существования объектов и не могут быть отменены.
Я реализую тогда так.
private FooThingy _foo;
public FooThingy Foo
{
set { if (null == _foo) _foo = value; }
get { return _foo; }
}
Но мне это не нравится. Я чувствую, что что-то упустил. Есть я?
Изменить: Почему у меня нет этого в конструкторе.
Я не могу вдаваться в подробности, но установка этого приводит к <
плохая аналогия>
Таяние восковой статуи <
/ плохая аналогия>
, И я не хочу, чтобы мой конструктор создавал уже расплавленные объекты.
8 ответов
Установка свойств один раз нарушает принцип наименьшего удивления - вызывающая сторона ожидает, что когда свойство может быть установлено один раз, оно может быть установлено снова. (конечно, диапазон запрета и проверки совместимости - но они привязаны к определенным значениям или комбинациям значений).
Инициализируйте их в конструкторе.
В качестве альтернативы, если они слишком сложны, чтобы написать все конструкторы, используйте класс factory / builder:
ThingieBuilder tb = new ThingieBuilder();
tb.FooThingy = 17.23; // r/w properties
tb.BarThingy = 42;
tb.UseExtendedThingamagicAdapter = true;
Thingie t = tb.Create();
if (t.Bar==42) // r/o property
...
Или разделите параметры настройки в объекте конфигурации, который можно заменить или передать во время создания.
Я думаю, что дизайн будет более понятным для вызывающей стороны, если такие значения будут переданы в конструктор и вместо этого будут отображаться как свойства только для чтения. Если значение не может быть установлено во время построения, возможно, было бы целесообразно выдать исключение при попытке установить значение снова:
private FooThingy _foo;
public FooThingy Foo
{
set
{
if (null == _foo) { _foo = value; }
else { throw new WhatEverThatFitsException(); }
}
get { return _foo; }
}
Просто чтобы быть очень ясным: я никоим образом не поощряю использование свойств set-Once; Пример кода показывает только подход, который я мог бы использовать, если значение по какой-либо причине недоступно во время создания объекта. Это сказал; Я никогда не сталкивался с такой ситуацией ни в одном из проектов, в которых участвовал.
Я бы посоветовал установить их на стройке и, следовательно, сделать сеттеров частными. Это кажется более разумным способом.
Если вы собираетесь сделать это таким образом, бросьте какое-то исключение. По крайней мере, дайте разработчику понять, что вы не установили их значения, а не игнорировали их молча.
Просто создайте методы-установщики, а не свойства - и разрыв между ожиданием и поведением исчезнет. Метод может свободно генерировать исключение InvalidOperationException, но неожиданно сделать так, чтобы установщик свойства сделал это.
private FooThingy _foo;
public FooThingy Foo
{
get { return _foo; }
}
public void SetFooThingy(FooThingy value) {
if (Foo != null)
throw new InvalidOperationException("Foo is already set!");
_foo = value;
}
Я согласен с Фредриком, только чтение будет иметь больше смысла. Таким образом, вы можете объявить свою переменную только в конструкторе (или как часть объявления). Я думаю, что делать то, что вы делаете, не сразу ясно, что это то, чего вы хотите достичь.
Проверьте эту страницу MSDN.
Если FooThingy является объектом-значением, таким как int, он будет инициализирован 0 вместо нуля. В остальном все выглядит хорошо
Сделайте их только для чтения и установите их в конструкторе.
Сложно сказать по этому игрушечному примеру, но звучит так _foo
относительно важно для существования этого объекта. В этом случае это почти наверняка должно быть свойство только для чтения, которое инициализируется во время создания и не должно иметь никакого открытого установщика. Пользуйтесь неизменными объектами везде, где это возможно; это делает вашу жизнь намного проще!