[英]How to add a set accessor to an inherited read-only property
我有一个关于在 C# 中覆盖属性的问题。 这里已经有一个类似的问题,但答案对我来说并不令人满意。 假设我有这些课程:
class A
{
public int Prop { get; }
}
class B : A
{
public int Prop { get; set; }
}
现在如您所见,我想在子类中的属性 Prop 中添加一个 setter。 我想出了两个解决方案。 第一个是使属性虚拟并在 B 类中覆盖它,如下所示:
class A
{
public virtual int Prop { get; }
}
class B : A
{
public override int Prop { get; set; }
}
但不幸的是,编译器不允许我这样做。 我的第二个想法是使用“新”关键字:
class A
{
public virtual int Prop { get; }
}
class B : A
{
public new int Prop { get; set; }
}
现在一切似乎都有效,但由于一个细节,这对我来说并不是一个令人满意的解决方案。 例如,让我们考虑这段代码:
B b = new B();
b.Prop = 5;
A a = b;
Console.WriteLine(a.Prop);
您可能知道我在输出中得到 0,但我想得到 5。有没有办法解决这个问题?
您可以尝试显式实现属性的设置器。 这需要一个接口:
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;
}
}
但不幸的是,如果不强制转换为IPropSet
,则无法设置此属性:
((IPropSet)new B()).Prop = 1;
另一种选择是使用支持字段并在B
中将Prop
创建为new
的,如下所示:
class A
{
protected int prop;
public int Prop => prop;
}
class B : A
{
public new int Prop
{
get => prop;
set => prop = value;
}
}
示例用法:
var b = new B { Prop = 1 };
Console.WriteLine(((A)b).Prop); // 1
class A
中属性的set
-ter 应该是protected
。 您仍然可以覆盖它,并且在class A
及其子级之外仍然无法访问它。
编辑:我再次阅读了您的问题并在Visual Studio中测试了我编辑的答案(我第一次没有机会这样做)。
据我了解,除了覆盖属性之外,您还希望能够从类外部在子类上设置属性值,但不能在基类上设置它。
你可以尝试这样的事情:
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; }
}
}
}
这是输出:
我想一切都清楚了,但如果没有,请随时询问。 也许我仍然没有理解这个问题,甚至在我的回答中犯了一些错误。
在Console.WriteLine(a.Prop); 您引用 A.Prop,B 类中的新 Prop 用于重新定义。
当用作声明修饰符时,new 关键字显式隐藏从基类继承的成员。 当您隐藏继承的成员时,该成员的派生版本将替换基类版本。 这假定成员的基类版本是可见的,因为如果它被标记为私有或在某些情况下是内部的,它将已经被隐藏。 尽管您可以在不使用 new 修饰符的情况下隐藏公共或受保护成员,但您会收到编译器警告。 如果您使用 new 显式隐藏成员,它会抑制此警告。 微软文档
但你可以使用,
if (a is B bb)
{
Console.WriteLine(bb.Prop);
}
或者使用这个模式
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 不是 B 的子类,这不是继承的工作方式。 我不明白你为什么要这样做,我认为你误解了继承的完整概念
如果您建议:
class A
{
public int Prop { get; }
}
class B : A
{
public int Prop { get; set; }
}
它们是相同的属性。 如果您执行以下操作:
class A
{
public int Prop { get; }
}
class B : A
{
public int AnotherProp { get; set; }
}
你可以设置:
B instance = new B();
B.Prop = 5;
如果您想要做的是在子类中拥有一个具有相同名称的属性(不推荐),您可以这样做,而无需使用继承:
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;
或者你可以玩它,而不直接复制它。 只是一个例子,向您展示class as property
和inheritance
之间的区别
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.