Is there a way to have a private readonly field in a class that could be assigned a value anywhere in the class, but only once??
That is, I am looking for a private read
You could create a generic struct to automate the process:
public struct WriteOnce
{
private T? _value;
public T Value
{
get { return _value; }
set
{
if (_value.HasValue) throw new InvalidOperationException();
_value = value;
}
}
}
EDIT I just realized the above won't even compile. The compiler doesn't let _value's type to be Nullable, because the T in Nullable must be a non-nullable type.
Here's an implementation that will work a bit better:
public struct WriteOnce
{
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 x)
{
return x.Value;
}
public WriteOnce(T val)
{
_value = val;
_hasValue = true;
}
}
Note I said it would work better - not that it would work well. There are still some gotchas on using it:
First, the compiler will complain if it detects that you're trying to use it without assigning something to it first. Initializing it like so will take care of that:
WriteOnce foo = default(WriteOnce);
Second, even if it throws an exception on modification, C# will still happily let you overwrite it. So while this does encapsulate some of the functionality; you should still wrap it in a property to prevent misuse if it's going to end up exposed in an object's interface.
private WriteOnce _someInt = default(WriteOnce);
public int SomeInt
{
get { return _someInt; }
set { _someInt.Value = value; }
}
However, that still doesn't really get around the last egregious error I committed in the original snippet, which was creating a mutable struct. If you're doing a lot of something like this it might be worth violating that principle for the sake of not repeating yourself, but this is definitely a potential trap that would need to be commented carefully and kept out of any public interfaces.
If it's just a one-off, though, what others have suggested about just directly implementing a property is less complicated and safer.