简体   繁体   English

如何将 set 访问器添加到继承的只读属性

[英]How to add a set accessor to an inherited read-only property

I have a question about overriding properties in C#.我有一个关于在 C# 中覆盖属性的问题。 There already is a similar question here, but the answers are not satisfying for me.这里已经有一个类似的问题,但答案对我来说并不令人满意。 Let's say I have these classes:假设我有这些课程:

class A
{
    public int Prop { get; }
}

class B : A
{
    public int Prop { get; set; }
}

Now as you can see I want to add a setter to the property Prop in a subclass.现在如您所见,我想在子类中的属性 Prop 中添加一个 setter。 I came up with two solutions.我想出了两个解决方案。 The first one is making the property virtual and overriding it in class B like this:第一个是使属性虚拟并在 B 类中覆盖它,如下所示:

class A
{
    public virtual int Prop { get; }
}

class B : A
{
    public override int Prop { get; set; }
}

But unfortunately the compiler doesn't allow me to do this.但不幸的是,编译器不允许我这样做。 My second idea was to use a 'new' keyword:我的第二个想法是使用“新”关键字:

class A
{
    public virtual int Prop { get; }
}

class B : A
{
    public new int Prop { get; set; }
}

Now everything seemingly works, but it's not a satisfying solution for me because of one detail.现在一切似乎都有效,但由于一个细节,这对我来说并不是一个令人满意的解决方案。 Let's consider for instance this piece of code:例如,让我们考虑这段代码:

B b = new B();
b.Prop = 5;
A a = b;
Console.WriteLine(a.Prop);

You probably know that I get 0 here in my output, but I want to get 5. Is there any way to solve this problem?您可能知道我在输出中得到 0,但我想得到 5。有没有办法解决这个问题?

You could try to explicitly implement property's setter.您可以尝试显式实现属性的设置器。 This requires an interface:这需要一个接口:

public interface IPropSet
{
    int Prop { set; }
}

class A
{
    protected int prop;
    public int Prop => prop;
}

class B : A, IPropSet
{
    int IPropSet.Prop
    {
        set => prop = value;
    }
}

But unfortunately this property cannot be set without casting to IPropSet :但不幸的是,如果不强制转换为IPropSet ,则无法设置此属性:

((IPropSet)new B()).Prop = 1;

Another option is to use a backing field and to create the Prop as new in B as follows:另一种选择是使用支持字段并在B中将Prop创建为new的,如下所示:

class A
{
    protected int prop;
    public int Prop => prop;
}

class B : A
{
    public new int Prop
    {
        get => prop;
        set => prop = value;
    }
}

Sample usage:示例用法:

var b = new B { Prop = 1 };
Console.WriteLine(((A)b).Prop); // 1

Property's set -ter in class A should be protected . class A中属性的set -ter 应该是protected You will still be able to override it and it still won't be accessible outside class A and its children.您仍然可以覆盖它,并且在class A及其子级之外仍然无法访问它。

Edit : I've read your question once again and tested my edited answer in Visual Studio (I haven't had a chance to do it the first time).编辑:我再次阅读了您的问题并在Visual Studio中测试了我编辑的答案(我第一次没有机会这样做)。

As I understand, besides overriding the property, you want to be able to set property's value on a subclass, from outside the class, but not setting it on the base class.据我了解,除了覆盖属性之外,您还希望能够从类外部在子类上设置属性值,但不能在基类上设置它。

You could try something like this:你可以尝试这样的事情:

using System;

namespace PropertyInheritance
{
    public class Program
    {
        static void Main(string[] args)
        {
            A a1 = new A();
            B b1 = new B();

            a1.Prop = 1;
            b1.Prop = 2;

            Console.WriteLine($"a1.Prop = {a1.Prop}");
            Console.WriteLine($"b1.Prop = {b1.Prop}");

            Console.WriteLine($"a1.GetPropField() = {a1.GetPropField()}");
            Console.WriteLine($"b1.GetPropField() = {b1.GetPropField()}");

            B b2 = new B();
            b2.Prop = 5;
            A a2 = b2;
            Console.WriteLine($"a2.Prop = {a2.Prop}");

            Console.WriteLine($"a2.GetPropField() = {a2.GetPropField()}");

            Console.ReadLine();
        }
    }

    public class A
    {
        protected int prop;

        public virtual int Prop {
            get { return prop; }
            set { }
        }

        // test method - to check field's value
        public int GetPropField() => prop;
    }

    public class B : A
    {
        public override int Prop
        {
            get { return prop; }
            set { prop = value; }
        }
    }
}

Here is the output:这是输出:

在此处输入图像描述

I suppose everything is clear, but if not, please feel free to ask.我想一切都清楚了,但如果没有,请随时询问。 Maybe I still didn't understand the question, or even made some mistake in my answer.也许我仍然没有理解这个问题,甚至在我的回答中犯了一些错误。

On Console.WriteLine(a.Prop);Console.WriteLine(a.Prop); you reference to A.Prop, new in B class for Prop is for redefining.您引用 A.Prop,B 类中的新 Prop 用于重新定义。

When used as a declaration modifier, the new keyword explicitly hides a member that is inherited from a base class.当用作声明修饰符时,new 关键字显式隐藏从基类继承的成员。 When you hide an inherited member, the derived version of the member replaces the base class version.当您隐藏继承的成员时,该成员的派生版本将替换基类版本。 This assumes that the base class version of the member is visible, as it would already be hidden if it were marked as private or, in some cases, internal.这假定成员的基类版本是可见的,因为如果它被标记为私有或在某些情况下是内部的,它将已经被隐藏。 Although you can hide public or protected members without using the new modifier, you get a compiler warning.尽管您可以在不使用 new 修饰符的情况下隐藏公共或受保护成员,但您会收到编译器警告。 If you use new to explicitly hide a member, it suppresses this warning.如果您使用 new 显式隐藏成员,它会抑制此警告。 Microsoft docs 微软文档

在此处输入图像描述

but you can use,但你可以使用,

if (a is B bb)
{
    Console.WriteLine(bb.Prop);
}

Or use this pattern或者使用这个模式

class A
{
    public virtual int Prop { get; protected set; }
}
class B : A
{
     public void SetProp(int prop) => Prop = prop;
}


B b = new B();
b.SetProp(5);
A a = b;
Console.WriteLine(a.Prop);

A is not a subclass of B, this is not how inheritance works. A 不是 B 的子类,这不是继承的工作方式。 I don't understand why do you want to do this, I think you are mistaken the complete concept of inheritance我不明白你为什么要这样做,我认为你误解了继承的完整概念

In the case you proposes:如果您建议:

 class A
{
    public int Prop { get; }
}

class B : A
{
    public int Prop { get; set;  }
}

they are the same property.它们是相同的属性。 If you do a:如果您执行以下操作:

 class A
{
    public int Prop { get; }
}

class B : A
{
    public int AnotherProp { get; set;  }
}

you can set:你可以设置:

B instance = new B();
B.Prop = 5;

If what you want to do is having a property in a subclass with the same name (not recommended) you can do this, without working with inheritance:如果您想要做的是在子类中拥有一个具有相同名称的属性(不推荐),您可以这样做,而无需使用继承:

internal class A
{
    internal int Prop { get; }
}

internal class B 
{
    internal A MySubClass { get; set;  }
}

B instanceB = new B();
A instanceA = new A();
instanceA.Prop = 5;
B.MySubClass = instanceA;

or you can play with that, without copy it directly.或者你可以玩它,而不直接复制它。 Is just an example to show you the difference between class as property and inheritance只是一个例子,向您展示class as propertyinheritance之间的区别

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM