允许向接口属性添加访问器,但不允许向抽象属性添加访问器

发布于 2025-01-07 00:07:42 字数 866 浏览 1 评论 0原文

为什么以下是合法的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

南薇 2025-01-14 00:07:42

因为使用接口的调用者只关心接口的实现者至少实现了接口的定义,如 @davisoa 所说,而示例中的 SomeAbstractClass 定义了一个公共合约,其中准确说明成员的类型、可访问性和(对于属性)可读性/可写性。

如果您使用反射来获取 SomeProperty 的 PropertyInfo(从基类或子类),它需要从某个地方解析该信息。允许子类更改可读性/可写性与更改返回类型或参数列表一样违反合同。

想象一下例如:

SomeAbstractClass sc = new SomeClassExtendingAbstractClass();
PropertyInfo pi = sc.GetType().GetProperty("SomeProperty");
Console.Out.WriteLine(pi.CanWrite); // What should be printed here?

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:

SomeAbstractClass sc = new SomeClassExtendingAbstractClass();
PropertyInfo pi = sc.GetType().GetProperty("SomeProperty");
Console.Out.WriteLine(pi.CanWrite); // What should be printed here?
纵山崖 2025-01-14 00:07:42

这是因为接口实现承诺将有一个您可以“获取”的属性 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.

も星光 2025-01-14 00:07:42

这是设计使然。我引用的是 C# 语言规范:

重写属性声明必须指定完全相同的属性
可访问性修饰符、类型和名称作为继承的属性,if
继承的属性只有一个访问器(即...仅准备就绪
或只写),覆盖属性必须仅包括
访问器。

这种决定背后的原因可能是因为接口是比抽象类更灵活的契约类型。接口只关心最小公分母而不是整个实现。我认为选择一种设计而不是另一种设计是有充分理由的。

This is by design. I am quoting from the C# language specs:

An overriding property declaration must specify the exact same
accessibility modifiers, types and name as the inherited property, if
the inherited property has only a single accessor (i.e.,... ready only
or write-only), the overriding property must include only that
accessor.

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.

独享拥抱 2025-01-14 00:07:42

您正在尝试覆盖不存在的集合运算符。要么在抽象类中定义属性的一组部分,要么不要尝试在具体类中定义属性。由于您在具体类中将集合设置为受保护,因此我猜测您想要做的是在抽象定义中创建一个受保护的集合运算符。

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.

情话墙 2025-01-14 00:07:42

必要的是覆盖现有属性并使用新的读写属性对其进行隐藏。不幸的是,.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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文