Вы можете создать общую структуру для автоматизации процесса:
public struct WriteOnce<T>
{
private T? _value;
public T Value
{
get { return _value; }
set
{
if (_value.HasValue) throw new InvalidOperationException();
_value = value;
}
}
}
EDIT
Я просто понял, что вышеупомянутое даже не скомпилируется. Компилятор не позволяет типу _value быть Nullable, потому что T в Nullable должен быть ненулевым типом.
Вот реализация, которая будет работать немного лучше:
public struct WriteOnce<T>
{
private T _value;
private bool _hasValue;
public bool HasValue { get { return _hasValue; } }
public T Value
{
get { return _value; }
set
{
if (HasValue) throw new InvalidOperationException();
_value = value;
_hasValue = true;
}
}
public static implicit operator T(WriteOnce<T> x)
{
return x.Value;
}
public WriteOnce(T val)
{
_value = val;
_hasValue = true;
}
}
Заметьте, я сказал, что это будет работать лучше, а не то, что это будет работать хорошо. Есть еще несколько ошибок по его использованию:
Во-первых, компилятор будет жаловаться, если обнаружит, что вы пытаетесь его использовать, не назначая ему что-то сначала. Инициализация, как это, позаботится об этом:
WriteOnce<int> foo = default(WriteOnce<int>);
Во-вторых, даже если оно вызывает исключение при модификации, C # все равно с радостью позволит вам перезаписать его. Так что, хотя это действительно заключает в себе некоторые функции; вы все равно должны обернуть его в свойство, чтобы предотвратить неправильное использование, если оно в конечном итоге будет открыто в интерфейсе объекта.
private WriteOnce<int> _someInt = default(WriteOnce<int>);
public int SomeInt
{
get { return _someInt; }
set { _someInt.Value = value; }
}
Однако, это все еще не позволяет обойти последнюю вопиющую ошибку, которую я совершил в исходном фрагменте, который создавал изменяемую структуру. Если вы делаете что-то подобное, возможно, стоит нарушать этот принцип ради того, чтобы не повторяться, но это определенно потенциальная ловушка, которую необходимо тщательно прокомментировать и не допускать. любые публичные интерфейсы.
Однако, если это всего лишь один раз, то, что другие предложили о прямой реализации свойства, является менее сложным и безопасным.