子类构造函数中的只读字段作为目标。

23

如果您有一个变量在对象实例化时已知且之后不应更改,应使用只读字段。

然而,在子类的构造函数中不允许给只读字段赋值。 即使超类是抽象的,这也行不通。

是否有人能好好解释一下为什么这不是个好主意,或者为什么C#语言中缺少此功能?

abstract class Super
{
    protected readonly int Field;
}

class Sub : Super 
{
    public Sub()
    {
        this.Field = 5; //Not compileable
    }
}

提示:你当然可以通过在超类中的受保护的构造函数中分配只读字段来达到相同的结果。


1
编译器错误也不准确:错误 68:只读字段不能被赋值(除了在构造函数或变量初始化器中) - nicodemus13
5个回答

14

我能想到的唯一原因是,根据规范,“它只是被设计成这样”。

只有在声明的时候、在同一个类中的实例构造函数或静态构造函数中才能直接分配给只读字段。

只读的重点在于它不能被更改,如果派生类可以修改,则不再属于只读,将会违反封装(通过修改另一个类的内部)。


1
是的没错。但对于抽象类来说还是不合适吗?也许是因为存在多个子类的可能性。 - philipshield
2
这可能是不合适的,也许我们永远不会知道那个设计决策的确切原因。 - m.edmondson
1
我不明白为什么对于抽象类来说这是不合适的,因为它们可以有构造函数,因此只读字段可以正常工作。 - pauloya

13
public class Father
{
    protected readonly Int32 field;

    protected Father (Int32 field)
    {
        this.field = field;
    }
}

public class Son : Father
{
    public Son() : base(5)
    {

    }
}

你可以尝试像这样做!


是的,我在我的问题中提到了这一点 :) 另外,alexm大约10分钟前发布了完全相同的答案。 - philipshield
2
这不是一个编辑,但别在意!这是一个很好的解决方法。 - philipshield
1
这正是我在寻找的解决方案。这只是挑剔,但我会做一个小修改来加强只读性(不是一个词):在Son类中声明一个变量“private readonly Int32 CONCRETE_FIELD = 5”。然后对于构造函数“public Son() : base (CONCRETE_FIELD) { }”。 - Michael Kaldwid

2
我会将其建模为C#中的抽象/虚拟属性。
abstract class Super {
  protected abstract int Field { get; }
}

class Sub : Super {
  protected override int Field { get { return 5; } }
}

在我看来,这比将每个只读字段作为参数包含在构造函数中更好。一方面,编译器也能够内联此操作,另一方面,构造函数的解决方案在派生类中会变成这样:

class Sub : Super {
  public Sub() : base(5) { } // 5 what ?? -> need to check definition of super class constructor
}

如果您已经有一个接受单个 int 值的构造函数,则此方法可能无法起作用。


0

我想主要原因是对于所有.NET语言实现来说增加了额外的复杂性。

此外,总有一个简单的解决方法:

 abstract class Super
 {
     protected readonly int Field;

     protected Super(int field)
     {
          this.Field = field;
     }
 }


class Sub : Super {
   public Sub():base(5)
   {
   }

}


0

我更倾向于使用超类中的受保护构造函数(如alexm所提到的),并结合XML注释。 这应该消除DonAndre在他的代码注释中提到的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接