È possibile eseguire il rollover (vedere la fine della risposta per un'implementazione più solida che sia thread-safe e supporti valori predefiniti).
public class SetOnce<T>
{
private bool set;
private T value;
public T Value
{
get { return value; }
set
{
if (set) throw new AlreadySetException(value);
set = true;
this.value = value;
}
}
public static implicit operator T(SetOnce<T> toConvert)
{
return toConvert.value;
}
}
Si può usare in questo modo:
public class Foo
{
private readonly SetOnce<int> toBeSetOnce = new SetOnce<int>();
public int ToBeSetOnce
{
get { return toBeSetOnce; }
set { toBeSetOnce.Value = value; }
}
}
più robusta implementazione di sotto
public class SetOnce<T>
{
private readonly object syncLock = new object();
private readonly bool throwIfNotSet;
private readonly string valueName;
private bool set;
private T value;
public SetOnce(string valueName)
{
this.valueName = valueName;
throwIfGet = true;
}
public SetOnce(string valueName, T defaultValue)
{
this.valueName = valueName;
value = defaultValue;
}
public T Value
{
get
{
lock (syncLock)
{
if (!set && throwIfNotSet) throw new ValueNotSetException(valueName);
return value;
}
}
set
{
lock (syncLock)
{
if (set) throw new AlreadySetException(valueName, value);
set = true;
this.value = value;
}
}
}
public static implicit operator T(SetOnce<T> toConvert)
{
return toConvert.value;
}
}
public class NamedValueException : InvalidOperationException
{
private readonly string valueName;
public NamedValueException(string valueName, string messageFormat)
: base(string.Format(messageFormat, valueName))
{
this.valueName = valueName;
}
public string ValueName
{
get { return valueName; }
}
}
public class AlreadySetException : NamedValueException
{
private const string MESSAGE = "The value \"{0}\" has already been set.";
public AlreadySetException(string valueName)
: base(valueName, MESSAGE)
{
}
}
public class ValueNotSetException : NamedValueException
{
private const string MESSAGE = "The value \"{0}\" has not yet been set.";
public ValueNotSetException(string valueName)
: base(valueName, MESSAGE)
{
}
}
fonte
2009-05-08 13:32:38
Questo mi odora, mi dispiace. Perché non passare il valore in un costruttore? Inoltre, hai intenzione di fornire il feed al chiamante in modo che possano controllare prima di impostare il valore, per assicurarsi che non sia stato impostato? –
Idealmente lo passerei nel costruttore, ma devo costruire l'oggetto su per un periodo di tempo. ad esempio un record fornisce l'informazione A, il record successivo fornisce le informazioni B e C. Una volta che ho un set completo di informazioni, quindi uso queste informazioni per collegare tutti i record di nuovo insieme. Volevo un meccanismo di runtime per verificare di aver impostato i valori solo una volta, rendendoli psuedo in sola lettura! –
E sì - puzza anche per me! –