【问题标题】:Adding accessor to interface property allowed, but not to abstract property允许向接口属性添加访问器,但不能向抽象属性添加访问器
【发布时间】:2012-03-11 00:32:03
【问题描述】:

为什么下面的 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

允许前者却不允许后者的原因是什么?

【问题讨论】:

  • 我认为这里的关键词是“覆盖”。没有设置方法可以覆盖。
  • 还是说override关键字是在属性级别而不是访问器级别指定的?毕竟,归根结底,每个访问器都是不同的方法。
  • 对 - 抽象关键字在属性级别起作用,而不是访问器级别。

标签: c# .net interface abstract-class


【解决方案1】:

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

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

想象一下:

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

【讨论】:

    【解决方案2】:

    这是因为接口实现承诺将有一个属性SomeProperty 可以“获取”。

    抽象类实现承诺它的子类将提供属性SomeProperty 的实现以及公共get 方法。

    最后,基类定义了一些必须覆盖的东西,而接口定义了一个契约

    【讨论】:

    • 就我而言,SomeClassExtendingAbstractClass 确实 提供了一个带有公共 get 方法的属性 SomeProperty。对于任何使用抽象接口的人来说,还有一个 setter 是无关紧要的。因此,我的问题。想象一下,如果每个 get/set 都是方法。想象一下,不能仅仅因为您扩展了具有GetValue 方法的抽象类而无法提供SetValue 方法。
    • @KentBoogaart 就是这样——他们不仅仅是吸气剂和二传手。属性是 .NET 中的一等公民,并且具有与属性相关联的关于其可读性/可写性的合同元数据。
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        需要的是覆盖现有属性并使用新的读写属性对其进行隐藏。不幸的是,.net 没有提供任何方法来覆盖和隐藏单个类中的成员。最好的办法可能是让抽象基类定义一个具体的非虚拟只读属性,其 getter 调用抽象函数。然后,派生类可以使用非虚拟读写函数来隐藏属性,该函数在其 getter 中调用相同的函数,并在其 setter 中调用新的抽象或虚函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-05-20
          • 2015-01-24
          • 2016-10-11
          • 1970-01-01
          • 2016-06-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多