У меня есть класс с двумя readonly int
полями. Они выставлены как свойства:
public class Thing
{
private readonly int _foo, _bar;
/// <summary> I AM IMMUTABLE. </summary>
public Thing(int foo, int bar)
{
_foo = foo;
_bar = bar;
}
public int Foo { get { return _foo; } set { } }
public int Bar { get { return _bar; } set { } }
}
Тем не менее, это означает, что следующее является совершенно законным кодом:
Thing iThoughtThisWasMutable = new Thing(1, 42);
iThoughtThisWasMutable.Foo = 99; // <-- Poor, mistaken developer.
// He surely has bugs now. :-(
Ошибки, возникающие при предположении, что это сработает, наверняка будут коварными. Несомненно, ошибочный разработчик должен был прочитать документы. Но это не меняет того факта, что ни одна ошибка компиляции или времени выполнения не предупредила его о проблеме.
Как следует Thing
изменить класс, чтобы разработчики с меньшей вероятностью допустили вышеуказанную ошибку?
Бросить исключение? Использовать метод получения вместо свойства?
c#
object-oriented
immutability
properties
kdbanman
источник
источник
Interfaces
. Я не уверен, что это то, что я делаю.Ответы:
Зачем делать этот код легальным?
Вынь,
set { }
если ничего не получится .Вот как вы определяете публичное свойство только для чтения:
источник
public int Foo { get; }
(авто-свойство только с геттером), ноpublic int Foo { get; private set; }
есть.В C # 5 и ранее мы столкнулись с двумя вариантами неизменяемых полей, доступных через геттер:
readonly
чтобы уничтожить неизменность. Хотя она создала много кода-шаблона).Хотя с C # 6 (доступно в VS2015, который был выпущен вчера), мы теперь получаем лучшее из обоих миров: автоматические свойства только для чтения. Это позволяет нам упростить класс ОП:
Foo = foo
ИBar = bar
линии действительны только в конструкторе (который достигает требования к надежным только для чтения) , а поле подложки подразумеваются, вместо того , чтобы быть явно определенно (который достигает более простой код).источник
Вы могли бы просто избавиться от сеттеров. Они ничего не делают, они сбивают с толку пользователей и приводят к ошибкам. Однако вместо этого вы можете сделать их закрытыми и, таким образом, избавиться от резервных переменных, упрощая ваш код:
источник
public int Foo { get; private set; }
Этот класс больше не является неизменным, потому что он может измениться сам. Спасибо хоть!readonly
Ключевое слово просто Защита от дурака, т.е. защищает от класса нарушающего immutablity в будущем; это не нужно для достижения неизменности, хотя.Два решения.
Просто:
Не включайте сеттеры, как отметил Дэвид, для неизменяемых объектов только для чтения.
В качестве альтернативы:
Разрешить сеттерам возвращать новый неизменный объект, более подробный по сравнению с первым, но предоставляющий состояние с течением времени для каждого инициализированного объекта. Этот дизайн - очень полезный инструмент для безопасности и неизменяемости потоков, который распространяется на все обязательные языки ООП.
ПСЕВДОКОД
публичная статическая фабрика
источник