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

Posted

技术标签:

【中文标题】只读字段作为子类构造函数的目标【英文标题】:readonly-fields as targets from subclass constructors 【发布时间】:2011-12-04 02:53:00 【问题描述】:

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

但是,不允许从子类的构造函数中分配只读字段。 如果超类是抽象的,这甚至不起作用。

有没有人能很好地解释为什么这不是一个好主意,或者缺乏 C# 语言?

abstract class Super

    protected readonly int Field;


class Sub : Super 

    public Sub()
    
        this.Field = 5; //Not compileable
    

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

【问题讨论】:

编译器错误也不准确:Error 68 A readonly field cannot be assigned to (except in a constructor or a variable initializer) 【参考方案1】:

我能看到的唯一原因是因为“它就是这样设计的”,根据spec:

对只读字段的直接分配只能作为其中的一部分发生 声明或在实例构造函数或静态构造函数中 同一班。

只读的关键是它不能被改变,如果派生类可以修改,那么这将不再是真的并且会违反封装(通过修改另一个类的内部)。

【讨论】:

确实如此。但是它仍然不适合抽象类吗?也许是因为可能有多个子类。 这可能是不恰当的,也许我们永远不会知道做出该设计决定的确切原因。 我不明白为什么它不适合抽象类,因为它们可以有构造函数,因此只读字段可以工作。【参考方案2】:
public class Father

    protected readonly Int32 field;

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


public class Son : Father

    public Son() : base(5)
    

    

你可以试试这样的东西!

【讨论】:

是的,我在我的问题中提到了这一点 :) 此外,alexm 大约 10 分钟前发布了完全相同的答案。 这不是编辑,但没关系!这是一个巧妙的解决方法 正是我正在寻找的解决方案。这只是吹毛求疵,但我会稍作修改以加强只读性(不是一个词):在 Son 类中声明一个变量“private readonly Int32 CONCRETE_FIELD = 5”。然后对于构造函数 "public Son() : base (CONCRETE_FIELD) .【参考方案3】:

我认为主要原因是所有 .NET 语言实现的额外复杂性

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

 abstract class Super
 
     protected readonly int Field;

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


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

【讨论】:

【参考方案4】:

我将通过 C# 中的抽象/虚拟属性对此进行建模。

abstract class Super 
  protected abstract int Field  get; 


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

在我看来,这比使用包含每个只读字段作为参数的构造函数更好的解决方案。一方面是因为编译器也能够内联 this 并且因为构造函数解决方案在派生类中看起来像这样:

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

如果您已经有一个采用单个 int 值的构造函数,这也可能不起作用。

【讨论】:

【参考方案5】:

我更喜欢在超类中使用受保护的构造函数(如 alexm 所述),与 xml cmets 一起使用。 这应该可以消除 DonAndre 在代码注释中所说的问题。

【讨论】:

以上是关于只读字段作为子类构造函数的目标的主要内容,如果未能解决你的问题,请参考以下文章

属性构造函数只读字段匿名类型

如何在构造函数的重载函数中使用子类中的字段值

使用父保护构造函数的实例子类字段

Spring基础篇(8)-Spring构造函数注入—实现子类的动态注入

Java 构造函数 - 子类构造函数中的可选参数

在子类中使用父类的对象。您需要将对象作为类构造函数传递吗?