为继承的只读字段分配值?

时间:2011-05-17 21:47:26

标签: c# inheritance constructor readonly

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

Readonly属性/字段允许您更改构造函数内部变量的值以及定义,但不能更改其他地方。如果我尝试在子类的构造函数中更改继承的只读变量的值,我会得到一个'readonly变量只能在构造函数中赋值'错误。为什么这样,如果没有反射,我该如何解决这个问题呢?

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

5 个答案:

答案 0 :(得分:22)

原因是您只能在该类的构造函数中分配 readonly 字段。
根据{{​​3}}(强调我的):

  

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

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

一个例子:

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)
        {}
    }
}

答案 1 :(得分:8)

您可以使用虚拟仅获取属性来获取您正在寻找的确切行为。

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

字段超出了继承和重载模型的范围,不应用于提供多态功能。

答案 2 :(得分:7)

亚当有正确的答案。如果你担心它将占用的空间(构造函数中的参数数量?)那么你应该将其解决为另一个解决方案的另一个问题:创建一个包含所有这些属性的BaseConfig类,这就是全部需要传入.Base然后可以从BaseConfig的属性中分配它的所有只读字段,或者你可以让Base只保留一个类型为BaseConfig的只读字段,并为值指代。

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

答案 3 :(得分:3)

您可以将属性与public get accessor和protected set accessor一起使用。派生类可以设置此属性的值。

一个例子:

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

答案 4 :(得分:0)

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