允许向接口属性添加访问器,但不允许向抽象属性添加访问器
为什么以下是合法的 C#:
public interface ISomeInterface
{
int SomeProperty
{
get;
}
}
public class SomeClassImplementingInterface : ISomeInterface
{
public int SomeProperty
{
get { return 32; }
protected set {}
}
}
而这不是:
public abstract class SomeAbstractClass
{
public abstract int SomeProperty
{
get;
}
}
public class SomeClassExtendingAbstractClass : SomeAbstractClass
{
public override int SomeProperty
{
get { return 32; }
protected set {}
}
}
后者会导致以下编译时错误:
'InterfaceAbstractTest.SomeClassExtendingAbstractClass.SomeProperty.set': 无法覆盖,因为 'InterfaceAbstractTest.SomeAbstractClass.SomeProperty' 没有 可重写的集合访问器 InterfaceAbstractTest
不禁止后者而允许前者的原因是什么?
Why is it that the following is legal C#:
public interface ISomeInterface
{
int SomeProperty
{
get;
}
}
public class SomeClassImplementingInterface : ISomeInterface
{
public int SomeProperty
{
get { return 32; }
protected set {}
}
}
but this is not:
public abstract class SomeAbstractClass
{
public abstract int SomeProperty
{
get;
}
}
public class SomeClassExtendingAbstractClass : SomeAbstractClass
{
public override int SomeProperty
{
get { return 32; }
protected set {}
}
}
The latter results in the following compile-time error:
'InterfaceAbstractTest.SomeClassExtendingAbstractClass.SomeProperty.set':
cannot override because
'InterfaceAbstractTest.SomeAbstractClass.SomeProperty' does not have
an overridable set accessor InterfaceAbstractTest
What is the reasoning for not disallowing the latter whilst allowing the former?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
因为使用接口的调用者只关心接口的实现者至少实现了接口的定义,如 @davisoa 所说,而示例中的
SomeAbstractClass
定义了一个公共合约,其中准确说明成员的类型、可访问性和(对于属性)可读性/可写性。如果您使用反射来获取
SomeProperty
的 PropertyInfo(从基类或子类),它需要从某个地方解析该信息。允许子类更改可读性/可写性与更改返回类型或参数列表一样违反合同。想象一下例如:
Because a caller using the interface only cares that an implementer of the interface at least implements the interface's definition, as @davisoa states, whereas
SomeAbstractClass
in your example defines a public contract which states exactly the type, accessibility, and (for properties) readability/writability of members.If you use reflection to get the PropertyInfo of
SomeProperty
(from either the base or child class), it needs to resolve that information from somewhere. Allowing the child class to change the readability/writability would be as much of a contract violation as a change in return type or argument list.Imagine for instance:
这是因为接口实现承诺将有一个您可以“获取”的属性
SomeProperty
。抽象类实现承诺它的子类将提供具有公共 get 方法的属性
SomeProperty
的实现。最后,基类定义了一些必须重写的东西,而接口则定义了契约。
This is because the Interface implementation is making a promise that there will be a property
SomeProperty
that you can "Get".The abstract class implementation is making a promise that it's child classes will provide an implementation of a property
SomeProperty
with a public get method.In the end, the base class is defining something that must be overridden, whereas the interface is defining a contract.
这是设计使然。我引用的是 C# 语言规范:
这种决定背后的原因可能是因为接口是比抽象类更灵活的契约类型。接口只关心最小公分母而不是整个实现。我认为选择一种设计而不是另一种设计是有充分理由的。
This is by design. I am quoting from the C# language specs:
The reason behind that decesion could be because the interfaces are more flexibly type of contracts than abstract classes. Interfaces cares only about the least common denominator rather than the whole implementation. I think there are good reasons to choose one design over the other.
您正在尝试覆盖不存在的集合运算符。要么在抽象类中定义属性的一组部分,要么不要尝试在具体类中定义属性。由于您在具体类中将集合设置为受保护,因此我猜测您想要做的是在抽象定义中创建一个受保护的集合运算符。
You're trying to override a set operator that doesn't exist. Either define a set portion of the property in the abstract class, or don't try to define one in the concrete class. Since you have the set as protected in the concrete class, my guess is what you want to do is make a protected set operator in the abstract definition.
必要的是覆盖现有属性并使用新的读写属性对其进行隐藏。不幸的是,.net 不提供任何方法来覆盖和隐藏单个类中的成员。最好的办法可能是让抽象基类定义一个具体的非虚拟只读属性,其 getter 调用一个抽象函数。然后,派生类可以使用非虚拟读写函数来隐藏该属性,该函数在其 getter 中调用相同的函数,并在其 setter 中调用新的抽象或虚拟函数。
What is necessary is to both override the existing property and shadow it with a new read-write one. Unfortunately, .net does not provide any means of both overriding and shadowing a member within a single class. The best one can do is probably to have the abstract base class define a concrete non-virtual read-only property whose getter calls an abstract function. A derived class can then shadow the property with a non-virtual read-write function which calls the same function in its getter, and a new abstract or virtual function in its setter.