可以在构造函数外部分配值的只读字段

有没有办法在类中有一个私有只读字段,可以在类中的任何位置分配值,但只有一次?

也就是说,我正在寻找一个私有只读类型的字段,它只能被赋值一次,但不一定在构造函数中。 因此,如果将一个值重新分配给一个字段,那么它会显示编译时错误(我确信这要求太多)。

如果有任何模式(不是语言特征)可以做同样的工作,那么真的有兴趣知道这一点。

谢谢你的关注。

最简洁的答案是不。 您可以进行编译器检查的一次性分配的唯一位置是构造函数。 您可以创建一个系统,如果多次尝试分配但是没有C#构造执行此操作会导致运行时错误

您不会收到编译时错误,但您可以使用属性完成您要查找的内容。 在setter中,仅在内部bool / flag为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; } } 

您可以创建一个通用结构来自动化该过程:

 public struct WriteOnce { private T? _value; public T Value { get { return _value; } set { if (_value.HasValue) throw new InvalidOperationException(); _value = value; } } } 

编辑我刚刚意识到上面甚至不会编译。 编译器不允许_value的类型为Nullable,因为Nullable中的T必须是非可空类型。

这是一个可以更好地工作的实现:

 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; } } 

注意我说它会更好 – 而不是它会运作良好。 使用它还有一些问题:

首先,如果编译器检测到您正在尝试使用它而不首先为其分配内容,则会抱怨。 像这样初始化它将照顾到:

 WriteOnce foo = default(WriteOnce); 

其次,即使它在修改时抛出exception,C#仍然会很乐意让你覆盖它。 所以虽然这确实封装了一些function; 你仍然应该将它包装在一个属性中,以防止误用,如果它最终暴露在对象的界面中。

 private WriteOnce _someInt = default(WriteOnce); public int SomeInt { get { return _someInt; } set { _someInt.Value = value; } } 

然而,这仍然没有真正解决我在原始片段中提交的最后一个令人震惊的错误,该错误创建了一个可变结构。 如果你做了很多像这样的事情,为了不重复自己, 可能值得违反这个原则,但这绝对是一个潜在的陷阱,需要仔细评论并保持在任何公共接口之外。

但是,如果它只是一次性的话,其他人建议的直接实施房产的方法则不那么复杂和安全。

您可以使用私有属性来检查它是否已分配给它,如果尚未分配值,则只分配值。

 int? _writeOnceField; private int? WriteOnce { set { if (!_writeOnceFiled.HasValue) { writeOnceFiled = value; } else { // Throw exception } } } 

没有语言支持,但你可以制作一个实现所需行为的setter。 显然,这不会给你编译时错误,但没有语言支持,这可能是你可以做的最好的。

这看起来像是声明分配或单身人士的好候选人。

 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 } //(...) }