Readonly字段vs抽象getter-only属性

kni*_*ttl 5 c# language-agnostic

与继承者实现一个抽象的getter-only属性相比,拥有readonly字段有什么优点和缺点(在这里使用C#作为例子,但我想这并不重要).

以下是两种方法:

  1. 只读字段; 继承者必须在构造函数中注入值

    interface IFace {
      public int Field { get; }
    }
    
    abstract class Base : IFace {
      private readonly int field;
    
      protected Base(int field) {
        this.field = field;
      }
    
      public int Field { get { return this.field; } }
    }
    
    class Impl {
      public Impl() : base(1) {
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 抽象的getter-only属性; 继承者必须实现该属性

    interface IFace {
      public int Field { get; }
    }
    
    abstract class Base : IFace {
      // default constructor can be used
    
      public abstract int Field { get; }
    }
    
    class Impl {
      public override int Field { get { return 1; } }
    }
    
    Run Code Online (Sandbox Code Playgroud)

这两个实现都公开了一个int Field不会改变的公共getter-only属性.

但是,我可以看到以下差异:

  1. field绑定到每个实例,没有什么能阻止继承者允许在其构造函数本身中接收值(public Impl(int field) : base(field)).

    绑定到实例时,每个单个实例都需要该字段的内存.这可能不是什么大问题,但绝对值得记住.

    传达的意图是:该值只能在构造函数中设置,并且以后不能更改(不考虑反射).

  2. (返回)值Field绑定到每种类型,但是没有什么能阻止继承者在每次调用getter时生成/计算值,每次都可能返回不同的值.public overried int Field { get { return DateTime.UtcNow.Second; } }

    内存只需要"在IL中",因为该值(通常)不会存储在任何地方,但总是在返回之前计算(导致加载指令,仅此而已).

    传达的意图应该是:值绑定到类型(并且不应该在调用之间改变,但是没有办法强制它,对吧?).但更确切地说,意图是:您需要提供此属性,我不关心您如何实现它以及它返回的值.

我有什么重要的差异吗?是一个优先于另一个,还是需要根据具体情况决定?

我想我正在寻找一个构造/模式/语言功能,它将只读(常量)值绑定到一个类型,但是在实例级别公开该值.我知道我可以在每个继承类型中使用静态字段,但是没有办法从公共基础(或接口)强制执行此操作.此外,仅具有对此类型实例的引用时,无法调用静态字段.思考?我很高兴收到不同编程语言的答案

mur*_*zat 3

您给出的模式 1 和模式 2 之间有一个关键区别。

模式 1 不允许在构造类后返回不同的值,因为基类仅在构造函数中使用字段。

模式 2 允许子类在不同时间返回不同的值。基本上 - 如果子类决定覆盖,则基类不会强制执行任何操作。

因此,这实际上取决于您想要实现的目标和您的领域逻辑。

关于您试图实现的意图 - 在我看来 - 解决实现意图的方法之一是声明一个虚拟方法(类似于基类中的 getReadOnlyField() )而不是只读属性。然后 - 子类可以自由地重写虚拟方法 - 如果它们不重写 - 基本实现仍然会被强制执行。

这个问题不可能有任何一个正确答案。将有多种方法来解决这个问题。这一切都取决于您的要求。