如果我写课,那么一切都好
class C
{
protected int _attr;
int attr { get { return _attr; } }
}
class CWithSet : C
{
int attr { set { _attr = value; } }
}
但是,如果我写接口
interface I
{
int attr { get; }
}
interface IWithSet : I
{
int attr { set; }
}
然后我有了交战:“'IWithSet.attr'隐藏了继承成员'I.attr'。如果想要隐藏,请使用new关键字。”
如何写,以免得到警告?
答案 0 :(得分:6)
来自C#规范:接口的继承成员特别不是接口声明空间的一部分。因此,允许接口声明与继承成员具有相同名称或签名的成员。当发生这种情况时,派生的接口成员被称为隐藏基接口成员。隐藏继承的成员不会被视为错误,但它确实会导致编译器发出警告。要禁止警告,派生接口成员的声明必须包含new
修饰符,以指示派生成员旨在隐藏基本成员。 (Interface members)正确的实现是:
interface IWithSet : I
{
new int attr { get; set; }
}
答案 1 :(得分:3)
您可能想要考虑是否值得重新定义接口的语义。我的意思是,除了您定义为“I”的只读接口之外,只有一个单独的只写接口可能是有意义的。
以下是一个例子:
interface IReadOnly
{
int Attr { get; }
}
interface IWriteOnly
{
int Attr { set; }
}
interface I : IReadOnly, IWriteOnly
{
}
class CReadOnly : IReadOnly
{
protected int _Attr;
public int Attr
{
get { return _Attr; }
}
}
class C : CReadOnly, I
{
public int Attr
{
get { return base.Attr; }
set { _Attr = value; }
}
}
编辑:我将C.Attr属性的get部分更改为return base.Attr
而不是return _Attr;
,以便与原始问题中的代码示例更加一致。我也认为这更正确,因为你可能在CReadOnly.Attr中定义了更复杂的逻辑,你不想复制。
某些接口和类已从原始示例重命名。 “我”成为“IReadOnly”,“IWithSet”成为“我”。 “C”变为“CReadOnly”,“CWithSet”变为“C”。
这是为我编写的,没有任何警告。
编辑:这是为我编译的,没有关于接口成员的警告。我确实得到了关于隐藏CReadOnly类属性的C类'Attr属性的1个警告,但这应该是完全可以预料到的,因为隐藏/阴影是我的例子中发生的事情。一个奇怪的事情:我可以发誓我编译(并运行!)这段代码几次,并看到0警告。那时我很困惑,但是我放手了......但是现在我看到了正如我所期待的那样的警告。也许只是一个编译器故障。
答案 2 :(得分:1)
如果您想要具有相同名称的单独属性,请使用new。警告是不言自明的。
另一方面,你想要的似乎更像是:
#pragma warning disable CS0108
interface IWithSet : I
{
int attr { get; set; }
}
#pragma warning restore CS0108
答案 3 :(得分:0)
可能不完美,但有一种解决办法可能是:
interface IWithSet : I
{
void SetAttr(int value);
}
答案 4 :(得分:0)
如何:
interface IWithSet : I
{
new int attr { get; set; }
}
缺点是IWithSet将始终同时具有getter和setter,即使删除了'I'中的getter:
interface I { }
如果你定义这两个接口假设'我'将永远有getter,那么这种方法没有任何问题,这将在一个用于限制访问的接口层次结构中正常工作,而不是封装特定于a的逻辑抽象层(类似于典型的读/写类型结构,其中作者继承了读者对读者具有读取权限的SAFE假设的所有读者访问权限。)。