C# 可以在构造函数外部赋值的只读字段
是否有一种方法可以在类中的任何位置为私有只读字段赋值,但只能赋值一次 也就是说,我正在寻找一种私有的只读类型的字段,它只能被赋值一次,但不一定在构造函数内部。所以,如果一个值被重新分配给一个字段,那么它将显示编译时错误(我确信这要求太多) 如果有任何模式(不是语言特性)可以做同样的工作,我也会很有兴趣知道C# 可以在构造函数外部赋值的只读字段,c#,readonly,C#,Readonly,是否有一种方法可以在类中的任何位置为私有只读字段赋值,但只能赋值一次 也就是说,我正在寻找一种私有的只读类型的字段,它只能被赋值一次,但不一定在构造函数内部。所以,如果一个值被重新分配给一个字段,那么它将显示编译时错误(我确信这要求太多) 如果有任何模式(不是语言特性)可以做同样的工作,我也会很有兴趣知道 感谢您的关注。您不会遇到编译时错误,但您可以使用属性完成所需的操作。在setter中,仅当内部bool/标志为false时才设置该值。第一次设置后,将标志设置为true。如果另一段代码再次调用
感谢您的关注。您不会遇到编译时错误,但您可以使用属性完成所需的操作。在setter中,仅当内部bool/标志为false时才设置该值。第一次设置后,将标志设置为true。如果另一段代码再次调用setter,您可以抛出InvalidOperationException,让他们知道它已经初始化
private bool fieldAlreadySet = false;
private string field;
public string Field
{
get {return field;}
set
{
if (fieldAlreadySet) throw new InvalidOperationException("field already set");
this.field = value;
fieldAlreadySet = true;
}
}
您可以使用私有属性来检查它是否已指定,并且仅在未指定值时才指定值
int? _writeOnceField;
private int? WriteOnce
{
set
{
if (!_writeOnceFiled.HasValue)
{
writeOnceFiled = value;
}
else
{
// Throw exception
}
}
}
没有语言支持,但是您可以创建一个setter,它实现了所需的行为。显然,这不会给您带来编译时错误,但是如果没有语言支持,这可能是您所能做的最好的了 简短的回答是否定的。编译器检查的一次性赋值只能在构造函数中进行。您可以创建一个系统,如果多次尝试分配,但没有C#construct来执行此操作,则会出现运行时错误您可以创建一个通用结构来自动执行此过程:
public struct WriteOnce<T>
{
private T? _value;
public T Value
{
get { return _value; }
set
{
if (_value.HasValue) throw new InvalidOperationException();
_value = value;
}
}
}
公共结构写入
{
私人T?u值;
公共价值
{
获取{返回_值;}
设置
{
如果(_value.HasValue)抛出新的InvalidOperationException();
_价值=价值;
}
}
}
编辑
我刚刚意识到上面的内容甚至无法编译。编译器不允许_值的类型为Nullable,因为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;
}
}
公共结构写入
{
私人T_值;
私有布尔值;
公共bool HasValue{get{return\u HasValue;}}
公共价值
{
获取{返回_值;}
设置
{
if(HasValue)抛出新的InvalidOperationException();
_价值=价值;
_hasValue=true;
}
}
公共静态隐式运算符T(WriteOnce x)
{
返回x.值;
}
公开书写(T val)
{
_值=val;
_hasValue=true;
}
}
注意,我说它会更好——不是说它会很好地工作。在使用它时仍然存在一些问题:
首先,如果编译器检测到您试图使用它而没有首先为它分配某些内容,它会抱怨。像这样初始化它将解决以下问题:
WriteOnce<int> foo = default(WriteOnce<int>);
WriteOnce foo=默认值(WriteOnce);
其次,即使它在修改时抛出异常,C#仍然会很高兴地让您覆盖它。因此,虽然这确实封装了一些功能;如果它最终暴露在对象的接口中,您仍然应该将其包装在属性中以防止误用
private WriteOnce<int> _someInt = default(WriteOnce<int>);
public int SomeInt
{
get { return _someInt; }
set { _someInt.Value = value; }
}
private WriteOnce\u someInt=default(WriteOnce);
公共整数
{
获取{return\u someInt;}
设置{u someInt.Value=Value;}
}
然而,这仍然没有真正绕过我在原始代码片段中犯的最后一个严重错误,即创建可变结构。如果你正在做很多类似的事情,为了不重复你自己,违反这一原则可能是值得的,但这肯定是一个潜在的陷阱,需要仔细评论,并将其排除在任何公共接口之外
但是,如果只是一次性的,那么其他人建议直接实现一个属性就不那么复杂和安全了。这看起来是声明赋值或单例的好选择
public class SomeClass {
private readonly Type t = typeof(SomeClass);
}
或者,像其他人所说的那样,只使用setter创建一个内部属性,然后为其赋值
public class SomeClass {
private Type t;
internal Type Type {
set {
if (t == null) t = value;
}
}
}
我想我找到了一种方法,如果它是在构造函数中完成的。它也可以位于变量声明行上。 如果在这些上下文之外执行,您将收到一个错误:无法将只读字段分配给(构造函数或变量初始值设定项中除外)
很抱歉发布此消息,我没有注意标题中的“外部构造函数”部分。
public class BillLine
{
public BillLine(Bill bill)
{
m_Bill = bill;
}
private readonly Bill m_Bill;
public Bill Bill
{
get { return m_Bill; }
//supposed to be set only in the constructor
}
//(...)
}