【问题标题】:Assigning a value to an inherited readonly field?为继承的只读字段赋值?
【发布时间】:2011-05-17 21:47:26
【问题描述】:

所以我有一个有很多孩子的基类。这个基类定义了一些具有默认值的只读属性和变量。这些可能会有所不同,具体取决于孩子。

只读属性/字段允许您在构造函数和定义中更改变量的值,但不能在其他任何地方更改。如果我尝试更改子类构造函数中继承的只读变量的值,则会收到“只读变量只能在构造函数中分配”错误。为什么会这样?如果没有反射,我该如何解决这个问题?

我的意图:允许用户通过脚本进行扩展,他们只能更改某些字段一次。

【问题讨论】:

  • 我遇到了一个非常相似的问题,并且得到了一个answer,它允许您对成员进行单个分配。功能上只读,所有样板代码都在一个位置。

标签: c# inheritance constructor readonly


【解决方案1】:

原因是您只能在该类的构造函数中分配给 readonly 字段。
根据the definition of readonly in the C# Reference(强调我的):

当字段声明包含只读修饰符时,对该声明引入的字段的赋值只能作为声明的一部分或在同一类的构造函数中发生

要解决此问题,您可以在基中创建一个受保护的构造函数,该构造函数接受只读属性的参数。

一个例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Base b = new Child();
            Console.WriteLine(b.i);
            Console.Read();
        }
    }

    class Base
    {
        public readonly int i;

        public Base()
        {
            i = 42;
        }

        protected Base(int newI)
        {
            i = newI;
        }
    }

    class Child : Base
    {
        public Child()
            : base(43)
        {}
    }
}

【讨论】:

  • 此解决方案的唯一缺点是它不允许您计算要传递给基类的值。
  • @Kent:可以通过调用基类构造函数的参数列表中的静态方法来实现。见stackoverflow.com/questions/1651444/…
【解决方案2】:

您可以通过使用 virtual get only 属性获得您正在寻找的确切行为。

public class BSE
{
    virtual public int Prop 
    {
        get
        {
            return 6;
         }
     }
}
public class Derived : BSE
{
    public override int Prop
    {
         get
         {
             return 10;
         }
    }
 }

字段在继承和重载模型之外,不应用于提供多态特性。

【讨论】:

  • 这听起来更像;但与干净的public readonly int number = 5 相比,它仍然是一个相当大的跳跃。
  • @Ruirize 您要为只读字段分配一个常量?这听起来确实像是对只读字段的滥用,而您可能希望使用虚拟属性。
【解决方案3】:

亚当有正确的答案。如果您担心它将占用的空间(构造函数中的参数数量?),那么您应该使用不同的解决方案将其作为不同的问题来解决:创建一个 BaseConfig 类,它包含所有这些属性,仅此而已需要传入。然后,Base 可以从 BaseConfig 的属性中分配所有它的只读字段,或者您可以让 Base 只保存一个 BaseConfig 类型的只读字段并参考该字段的值。

至于为什么会这样,请参阅C# constructor execution order,了解每个类的只读字段何时会被初始化/可初始化。

【讨论】:

  • 这让我有点难过;我希望有一种非常好的方法来实现这一点,这样为我的引擎制作脚本会非常整洁和聪明。那好吧。 BaseConfig 类也可以工作,谢谢!
【解决方案4】:

您可以将属性与公共 get 访问器和受保护的 set 访问器一起使用。派生类可以设置该属性的值。

一个例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Base b = new Child();
            Console.WriteLine(b.I);
            Console.Read();
        }
    }

    class Base
    {
        public int I { get; protected set; }

        public Base()
        {
            I = 42;
        }
    }

    class Child : Base
    {
        public Child()
        {
            I = 43;
        }
    }
}

【讨论】:

  • protected 不是只读的。派生类可以在它们的构造函数之外设置它。
【解决方案5】:

这在设计上是不可能的。尝试将值传递给protected 基类构造函数

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-30
    • 2012-02-28
    • 2016-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多