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

时间:2012-02-20 16:52:12

标签: c# .net interface abstract-class

为什么以下是合法的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'没有   一个可覆盖的set访问器InterfaceAbstractTest

在允许前者的同时不解除后者的原因是什么?

5 个答案:

答案 0 :(得分:3)

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

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

想象一下:

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

答案 1 :(得分:2)

这是因为接口实现承诺会有一个属性SomeProperty,你可以"获取"。

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

  

重写属性声明必须指定完全相同   辅助功能修饰符,类型和名称作为继承属性, if   继承的属性只有一个访问者(即,...只有就绪   或只写),覆盖属性必须仅包含该属性   存取器。

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

答案 4 :(得分:0)

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