继承自动实现的属性,派生类中只需要 getter
本文关键字:getter 派生 实现 属性 继承 | 更新日期: 2023-09-27 18:33:46
我有下一个代码
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
乍一看,最后一行应该符合的事实似乎并不那么明显。在我的程序中,我遇到一种情况,即以这种方式覆盖某些自动实现的属性将是一种解决方案。我知道这不是一个好方法。我可以做什么样的重构来避免这种继承并清理我的代码?谢谢
生类必须实现与其基类相同的接口 - 如果从派生类无法访问公共资源库会破坏多态性。
如果客户端需要无法访问 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; }
}
class Base
{
public virtual int Prop { get; set; }
}
class Derived : Base
{
public new int Prop { get { return 1; } private set {} }
}
问题是,如果将派生转换为 Base,则无论如何都可以设置该属性。如果属性中继字段,它将被覆盖。
前任。:
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; } }
}
但我发现最后一个太"贵"了......:)
我认为在这种情况下不可能出现编译器错误。进一步想象一下,你会声明obj
不是Derived
而是Base = new Derived()
,编译器应该如何知道要推断哪个属性。因此,您所能做的就是在运行时在派生资源库中引发异常,告知不允许设置此属性此类型。
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
仍然是基类的。
如果这是你想要的行为,我不认为它是错的。
如果你试图在派生类中隐藏资源库,没有优雅的方法可以做到这一点,所以抛出一个 NotSupportedException 是一种解决方案。
class Base
{
public virtual int Prop { get; set; }
}
class Derived : Base
{
public override int Prop { get { return 1; } set { throw new NotSupportedException();}}
}