繁体   English   中英

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

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

我有下一个代码

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

乍看之下,最后一行应该符合这一事实似乎并不那么明显。 在我的程序中,我遇到这样的情况:以这种方式覆盖一些自动实现的属性将是一个解决方案。 我知道这不是一个好方法。 为了避免这种继承并清除我的代码,我可以进行哪种重构? 谢谢

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

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

问题在于,如果将“派生为基数”强制转换,则仍然可以设置该属性。 如果将属性中继到某个字段,它将被覆盖。

例如:

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

避免此类问题的“更好”方法是,如果要在派生类上进行“更改”,则避免使用基类。 或者,仅放置所有派生类必须实现的最少内容,并让派生类实现仅他们想要的任何额外代码。

例如:

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

另外,您可以“封装”您的基类:

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

但是我发现这最后一个太“贵”了... :)

派生类必须实现与其基类相同的接口-使派生类无法访问公共设置器会破坏多态性。

如果Prop需要客户端无法访问,但是您需要能够在类本身内部设置其值,则可以将其声明为:

public virtual int Prop { get; protected set; }

这个问题可能没有一个答案,因为这取决于您特定应用程序的模型。 如果某些派生类需要允许对该属性进行写操作,而另一些不允许,则可以在无效写操作上引发异常并在运行时对其进行处理,或者可以使用受保护的后备字段并且仅使用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; }
}

我认为在这种情况下不可能出现编译器错误。 进一步想象一下,您将obj声明为Derived而不是Derived而是Base = new Derived() ,编译器应如何知道要推断的属性。 因此,您所能做的就是在派生的setter中在运行时抛出一个异常,告诉您此类型不允许设置此属性。

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

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

编译时,C#将getter和setter转换为单独的方法(get_Prop和set_Prop)。 您的代码仅在Derived类中实现get ,而set仍保留基类的get

如果这是您想要的行为,我认为这不是错误的。

如果要在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