为继承的只读字段赋值?

发布于 2024-11-07 17:07:52 字数 220 浏览 6 评论 0原文

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

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

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

So I have a base class that has many children. This base class defines some readonly properties and variables that have default values. These can be different, depending on the child.

Readonly properties/fields allow you to change the value of the variable inside the constructor and also the definition, but nowhere else. I get a 'readonly variable can only be assigned to in a constructor' error if I try to change the value of an inherited readonly variable in the child class' constructor. Why is this and how can I work around this, without Reflection?

My intention: To allow user extensibility through scripts where they can only change certain fields once.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

太傻旳人生 2024-11-14 17:07:52

原因是您只能分配给该类的构造函数中的只读字段。
根据readonly的定义在 C# 参考 中(强调我的):

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

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

一个例子:

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

The reason is that you can only assign to readonly fields in the constructor of that class.
According to the definition of readonly in the C# Reference (emphasis mine):

When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.

To work around this, you could make a protected constructor in the base that takes a parameter for the readonly property.

An example:

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)
        {}
    }
}
无风消散 2024-11-14 17:07:52

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

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

字段位于继承和重载模型之外,不应用于提供多态功能。

You could get the exact behavior you are looking for by using virtual get only properties.

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

Fields are out side the inheritance and overloading model and should not be used to provide polymorphic features.

伏妖词 2024-11-14 17:07:52

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

至于为什么会这样,请参阅 C# 构造函数执行顺序了解每个类的只读字段何时初始化/可初始化。

Adam has the right answer. If you're worried about the space it will take up (number of parameters in the constructor?) then you should address that as a different problem with a different solution: create a BaseConfig class, that contains all those properties and that is all that needs to be passed in. Base can then either assign all it's readonly fields from BaseConfig's properties, or you can instead have Base hold just one readonly field of type BaseConfig and refer to that for the values.

As to why this is, see C# constructor execution order regarding when each class's readonly fields would be initialized/initializable.

甜尕妞 2024-11-14 17:07:52

您可以将属性与 public get 访问器和 protected 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;
        }
    }
}

You can use property with public get accessor and protected set accessor. Derived classes can set value of this property.

An example:

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;
        }
    }
}
蘑菇王子 2024-11-14 17:07:52

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

this is impossible by design. try passing the values to a protected base class constructor

眼眸里的快感 2024-11-14 17:07:52

这本质上就是 @rerun 的想法,但使用的是 abstract 而不是 virtual

protected abstract class BaseClass
{
    protected abstract int PrivateI { get; }
}

public class DerivedClass : BaseClass
{
    private readonly int _i;
    protected override int PrivateI => _i;

    public DerivedClass(int i)
    {
        _i = i;
    }
}

This is essentially what @rerun came up with, but with abstract instead of virtual:

protected abstract class BaseClass
{
    protected abstract int PrivateI { get; }
}

public class DerivedClass : BaseClass
{
    private readonly int _i;
    protected override int PrivateI => _i;

    public DerivedClass(int i)
    {
        _i = i;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文