我正在寻找一种方法来允许C#对象中的属性只设置一次.编写代码很容易,但我宁愿使用标准机制(如果存在).
public OneShot<int> SetOnceProperty { get; set; }
我想要发生的是,如果属性尚未设置,则可以设置属性,但如果之前已设置,则抛出异常.它应该像Nullable值一样运行,我可以检查它是否已设置.
Mar*_*ell 49
在.NET 4.0的TPL中直接支持这一点;
(编辑:上面的句子写的是预期System.Threading.WriteOnce<T>当时可用的"预览"位中存在的,但这似乎在TPL命中RTM/GA之前已经消失)
直到那时才自己做检查......从我记得的内容来看,并不多.
就像是:
public sealed class WriteOnce<T>
{
private T value;
private bool hasValue;
public override string ToString()
{
return hasValue ? Convert.ToString(value) : "";
}
public T Value
{
get
{
if (!hasValue) throw new InvalidOperationException("Value not set");
return value;
}
set
{
if (hasValue) throw new InvalidOperationException("Value already set");
this.value = value;
this.hasValue = true;
}
}
public T ValueOrDefault { get { return value; } }
public static implicit operator T(WriteOnce<T> value) { return value.Value; }
}
Run Code Online (Sandbox Code Playgroud)
然后使用,例如:
readonly WriteOnce<string> name = new WriteOnce<string>();
public WriteOnce<string> Name { get { return name; } }
Run Code Online (Sandbox Code Playgroud)
Mic*_*ows 30
您可以自己滚动(请参阅答案的结尾,以获得更强大的线程安全实现并支持默认值).
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;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以像这样使用它:
public class Foo
{
private readonly SetOnce<int> toBeSetOnce = new SetOnce<int>();
public int ToBeSetOnce
{
get { return toBeSetOnce; }
set { toBeSetOnce.Value = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
下面更强大的实现
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)
{
}
}
Run Code Online (Sandbox Code Playgroud)
Ton*_*Nam 19
public DateTime RecordedAt { get; init; }
Run Code Online (Sandbox Code Playgroud)
Ant*_*lev 11
这可以通过摆弄旗帜来完成:
private OneShot<int> setOnce;
private bool setOnceSet;
public OneShot<int> SetOnce
{
get { return setOnce; }
set
{
if(setOnceSet)
throw new InvalidOperationException();
setOnce = value;
setOnceSet = true;
}
}
Run Code Online (Sandbox Code Playgroud)
这是不好的,因为您可能会收到运行时错误.在编译时强制执行此行为要好得多:
public class Foo
{
private readonly OneShot<int> setOnce;
public OneShot<int> SetOnce
{
get { return setOnce; }
}
public Foo() :
this(null)
{
}
public Foo(OneShot<int> setOnce)
{
this.setOnce = setOnce;
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用任一构造函数.
C# 中没有这样的功能(截至 3.5)。你必须自己编码。
| 归档时间: |
|
| 查看次数: |
32622 次 |
| 最近记录: |