简体   繁体   English

自动实现属性的继承,派生类中仅需要getter

[英]Inheritance of auto-implemented property with only getter needed in a derived class

I have next code 我有下一个代码

class Base
{
    public virtual int Prop { get; set; }
}

class Derived : Base
{
    public override int Prop { get { return 1; } }
}

//...
Derived obj = new Derived();
int some = obj.Prop; //expected
obj.Prop = 10; //oops it works

The fact that the last line should complile seems not to be so obvious at first sight. 乍看之下,最后一行应该符合这一事实似乎并不那么明显。 In my program I have a situation when overriding some auto-implemented property in a such way would be a solution. 在我的程序中,我遇到这样的情况:以这种方式覆盖一些自动实现的属性将是一个解决方案。 I understand that it's not a good approach. 我知道这不是一个好方法。 What kind of refactoring can I do to avoid such inheritance and to clean my code? 为了避免这种继承并清除我的代码,我可以进行哪种重构? Thanks 谢谢

class Base
{
    public virtual int Prop { get; set; }
}

class Derived : Base
{
    public new int Prop { get { return 1; } private set {}  }
}

The problem is that if you cast your Derived to Base, you can set the property anyway. 问题在于,如果将“派生为基数”强制转换,则仍然可以设置该属性。 If the Property relay on a field, it will be overwriten. 如果将属性中继到某个字段,它将被覆盖。

Ex.: 例如:

class Base
{
    protected int fProp;
    public virtual int Prop { get { return fProp; } set { fProp = value; } }
}

class Derived : Base
{
    public Derived()
    {
        fProp = 1;
    }
    public new int Prop { get { return fProp; } private set {}  }
}



namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            //...
            Derived obj = new Derived();
            int some = obj.Prop; //expected
            Base b = (Base)obj;
            b.Prop = 10; //oops it works
            Console.WriteLine(obj.Prop); =>it will show 10, not 1
            Console.ReadKey();
        }
    }
}

A "better" approach to avoid this kind of problem is to avoid the use of a base class if you want to "change" something on a derived class. 避免此类问题的“更好”方法是,如果要在派生类上进行“更改”,则避免使用基类。 Or, put only the minimal content that must be implemente by ALL derived classes and let the derived classes implement any extra code that only they want. 或者,仅放置所有派生类必须实现的最少内容,并让派生类实现仅他们想要的任何额外代码。

Ex: 例如:

class Base
{
    protected int fProp;
}

class Derived : Base
{
    public Derived()
    {
        fProp = 1;
    }
    public int Prop { get { return fProp; } }
}

class Derived2 : Base
{
    public int Prop { get { return fProp; }  set { fProp = value; } }
}



namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            //...
            Derived obj = new Derived();
            int some = obj.Prop; //expected
            Base b = (Base)obj;
            //obj.Prop = 10; Compilation error
            Console.WriteLine(obj.Prop);
            Derived2 obj2 = new Derived2();
            obj2.Prop = 10;
            Console.WriteLine(obj2.Prop);
            Console.ReadKey();
        }
    }
}

Also, you could "encapsulate" your base class: 另外,您可以“封装”您的基类:

class Derived
{
    protected Base fBase;

    public Derived()
    {
        fBase = new Base;
    }

    //implement enything that you need to access from Base class

    public int Prop { get { return 1; } }
}

But I find this last one too "expensive"... :) 但是我发现这最后一个太“贵”了... :)

A derived class has to implement the same interface as its base class - having a public setter be inaccessible from a derived class would break polymorphism. 派生类必须实现与其基类相同的接口-使派生类无法访问公共设置器会破坏多态性。

If Prop needs to be inaccessible to clients, but you need to be able to set its value from within the class itself, you could declare it as: 如果Prop需要客户端无法访问,但是您需要能够在类本身内部设置其值,则可以将其声明为:

public virtual int Prop { get; protected set; }

There probably isn't a single answer to this question, as it depends on the model for your specific application. 这个问题可能没有一个答案,因为这取决于您特定应用程序的模型。 If some derived classes need to allow writes to this property, but others don't, you could either throw an exception on an invalid write and handle it at run time, or perhaps implement the property using a protected backing field and only a getter, and then add a derived class that provides a SetProp() method for those classes that need it. 如果某些派生类需要允许对该属性进行写操作,而另一些不允许,则可以在无效写操作上引发异常并在运行时对其进行处理,或者可以使用受保护的后备字段并且仅使用getter来实现该属性,然后添加一个派生类,该类为需要该类的类提供SetProp()方法。

public class Base
{
    protected int prop;
    public virtual int Prop { get { return prop; } }
}

public class WriteableBase : Base
{
    public virtual void SetProp(int prop) { this.prop = prop; }
}

I think it´s not possible to get compiler-error in this case. 我认为在这种情况下不可能出现编译器错误。 Imagine further you´d declare obj not as Derived but as Base = new Derived() , how should compiler know which property to infer. 进一步想象一下,您将obj声明为Derived而不是Derived而是Base = new Derived() ,编译器应如何知道要推断的属性。 So all you can do is to throw an exception during runtime within the derived setter telling that setting this property isn´t allowed fir this type. 因此,您所能做的就是在派生的setter中在运行时抛出一个异常,告诉您此类型不允许设置此属性。

class Base
{
    public virtual int Prop { get; protected set; }
}

class Derived : Base
{
    public override int Prop { 
        get { return 1; } 
        protected set {throw NotSupportedException();}  
    }
}

When compiling, C# transforms the getter and setter to individual methods (get_Prop and set_Prop). 编译时,C#将getter和setter转换为单独的方法(get_Prop和set_Prop)。 Your code only implements the get in the Derived class, and the set remains that of the base class. 您的代码仅在Derived类中实现get ,而set仍保留基类的get

If this is your desired behavior, I don't find it to be wrong. 如果这是您想要的行为,我认为这不是错误的。

If you are trying to hide the setter in the Derived class, there is no elegant way to do it, so throwing an NotSupportedException is a solution. 如果要在Derived类中隐藏设置器,则没有优雅的方法,因此抛出NotSupportedException是一种解决方案。

    class Base
    {
        public virtual int Prop { get; set; }
    }

    class Derived : Base
    {
        public override int Prop { get { return 1; } set { throw new NotSupportedException();}}
    }

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

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