接口继承:是否可以扩展属性?

时间:2010-08-18 20:14:47

标签: c# inheritance interface properties

我想这样做:

interface IBase
{
    string Property1 { get; }
}

interface IInherited : IBase
{
    string Property1 { get; set; }
}

这样IInherited就会有继承的属性Property1,并添加了允许set的功能。

这可能吗?语法是什么?

编辑:请注意我将“继承”一词放在粗体字中。我具体要求继承该属性,而不是将其隐藏在新属性背后。

7 个答案:

答案 0 :(得分:24)

如果唯一的方法是使用new关键字困扰你,那么在我看来,你认为接口是错误的。

当然,您可以说IInherited“继承自”IBase;但这真的意味着什么?这些是接口;他们建立代码合同。通过使用IBase.Property1隐藏new string Property1 { get; set; }属性,您不会隐藏任何功能。因此,许多开发人员认为隐藏为“坏”事物的传统原因 - 它违反了多态性 - 在这种情况下无关紧要。

问问自己:在接口方面,至关重要是什么?它们提供了对某些方法调用做出响应的保证,对吗?

因此,给出以下两个接口:

interface IBase
{
    string Property1 { get; }
}

interface IInherited : IBase
{
    new string Property1 { set; }
}
  1. 如果对象实现IBase,您可以阅读其Property1属性。
  2. 如果对象实现了IInherited,您可以阅读其Property1属性(就像IBase实现一样),您也可以写入它。
  3. 同样,这里确实没什么问题。

答案 1 :(得分:2)

隐藏一名成员违反了Liskov替代原则,并且几乎不应该这样做。通过隐藏此成员,您将引入一个非常难以定位的错误,因为根据您是将对象转换为IBase1还是将其转换为IBase,将会发生2种不同的结果。

http://en.wikipedia.org/wiki/Liskov_substitution_principle

答案 2 :(得分:1)

你的代码应该仍然有用......它只是因为隐藏了Property1而创建了一个编译器警告。要使用新前缀

清除IInherited中的警告标记Property1

答案 3 :(得分:1)

不明确,不。您有两种选择:

public interface IBase
{
    string Property1 { get; }
}

public interface IInherited : IBase
{
    void SetProperty1(string value);
}

或者您可以使用new关键字终止编译器警告:

public interface IBase
{
    string Property1 { get; }
}

public interface IInherited : IBase
{
    new string Property1 { get; set; }
}

除非您明确实施IInherited.Property1,否则IBase会自动绑定到您的可设置实现。

答案 4 :(得分:1)

不幸的是没有 - 属性不能这样扩展。但是,您可以使用new隐藏属性:

interface IInherited : IBase
{
    // The new is actually unnecessary (you get warnings though), hiding is automatic
    new string Property1 { get; set; }
}

或者,您可以制作自己的getter和setter方法,这些方法可以覆盖(很好的'Java风格):

interface IBase
{
    string GetProperty1();
}
interface IInherited : IBase
{
    void SetProperty1(string str);
}

编译器实际上将属性转换为getter和setter方法。

答案 5 :(得分:0)

您可以使用“new”关键字标记属性,也可以跳过继承:

public interface IBase
{
    string Property1 { get; }
}

public interface IInherited : IBase
{
    new string Property1 { get; set; }
}

或者:

public interface IBase
{
    string Property1 { get; }
}

public interface IInherited
{
    string Property1 { get; set; }
}

无论哪种方式,这应该有效:

public class SomeClass : IInherited, IBase
{
    public string Property1
    {
        get
        {
            // ...
        }
        set
        {
            // ...
        }
    }
}

但是,在为接口创建继承链之前,您可能需要仔细思考。谁会看到哪个界面?通过IBase时你需要投射到IInherited吗?如果是这样,你可以保证你可以做那个演员表(如果你允许用户创建的类,那么答案是否定的)?如果你不小心,这种继承真的会伤害(重新)可用性。

答案 6 :(得分:0)

在我的工作中,我与几个首席开发人员进行了交谈,得出的结论是:

  • 这两种方法在技术上都是有效的。
  • 接口都是关于单一目的的。

接口用于定义任何继承类可以起作用的方式。即使您的第二个接口共享片段,或者甚至在某些相同的条件下使用,也将定义一个接口来解释如何在与该接口相关的所有条件下使用类。

此外,由于这个原因,类能够继承多个接口。在代码清晰度方面:

public class SomeClass : IInherited, IBase

上面显式的行指出SomeClass能够执行IInherited的动作和IBase的动作,并且其中某些动作相同是没有关系的。必须通过接口向后爬网以发现IInherited扩展了IBase,这可能会使其他可能在将来查看您代码的开发人员感到困惑。

这似乎是重复的工作,两个接口中的值都相同,但是您的代码功能没有任何假设。