Interface 实现两个或多个其他接口的标记接口

Interface 实现两个或多个其他接口的标记接口,interface,Interface,编写一个只为集中其他接口而存在的接口被认为是好的做法还是坏的做法 interface InterfaceA : InterfaceB, InterfaceC { } 在这样做的过程中,一个具体的实现只需要实现InterfaceA,这似乎是件好事,但它不会通过扩展增加任何价值,这似乎是浪费。如果这是有意义的,并且您将独立使用所有三个接口,那么它肯定是合适的设计决策 如果事实证明InterfaceB和InterfaceC永远不会被使用,那么只需使InterfaceA…它对于维护代码可读性确实很有用

编写一个只为集中其他接口而存在的接口被认为是好的做法还是坏的做法

interface InterfaceA : InterfaceB, InterfaceC {
}

在这样做的过程中,一个具体的实现只需要实现
InterfaceA
,这似乎是件好事,但它不会通过扩展增加任何价值,这似乎是浪费。

如果这是有意义的,并且您将独立使用所有三个接口,那么它肯定是合适的设计决策


如果事实证明InterfaceB和InterfaceC永远不会被使用,那么只需使InterfaceA…

它对于维护代码可读性确实很有用,那么您可以在需要接口B或C的地方使用接口A的具体实现。

我认为这取决于它在您的领域中是否有意义。如果是的话,我会这样做,那么你的程序会更准确地为你的领域建模


此外,当然,您现在可以编写需要/使用实现
InterfaceA
的对象的代码,即两个超级接口的所有方法;这在以前是不可能的。

我本想问同样的问题,但决定非常谨慎,进行广泛的搜索,以避免重复。然后我找到了这个——我编辑了这个标题,希望它会变得更受欢迎,因为它应该

首先,我们应该知道,像这样的空接口也被称为标记接口——考虑到我接下来要说的内容,Scott Wisniewsi的答案(目前位于顶部)很有趣

在研究空接口时,您通常会偶然发现这一点,这特别表明应该避免至少实现两个其他接口的空接口

因此,在你的例子中——当然不一定意味着微软的编码准则是事实上的——这正是你正在做的(我在当前项目中也想做的),因此它将通过微软自己的石蕊测试。因此,我很高兴地说‘是的,这样的界面是完全合理的’

为了说明理由,我认为一个特别好的例子说明了为什么在这个规则上设置“至少两个接口”开关的原因,它与我所处的情况类似:

public interface IReadsAResource
{
  public byte[] Read(string id);
}

public interface IWritesAResource
{
  //returns the id
  public string Write(byte[] resource);
}
考虑到这两个接口,我现在可以编写一个组件,明确说明它只需要读或写:

public class NeedsRead
{
  private readonly IReadsAResource Reader;
  public NeedsRead(IReadsAResource reader){ Reader = reader; }
}

public class NeedsWrite
{
  private readonly IWritesAResource Writer;
  public NeedsWrite(IWritesAResource writer){ Writer = writer; }
}
我现在通常会选择在单个类
ResourceReaderWriter
上实现此接口,因为资源的数据存储将需要两个方法实现共享的依赖项,在需要任何一个接口时传递该接口的实例:

var needsRead = new NeedsRead(new ResourceReaderWriter(/* dependencies */));
var needsWrite = new NeedsWriter(new ResourceReaderWriter(/* dependencies */));
但是如果我有一个类既需要读取又需要写入资源呢?由于接口生态系统目前已就位,我需要两个构造函数参数:

public class NeedsReadAndWrite{
  public NeedsReadAndWrite(IReadsAResource reader, IWritesAResource writer){
    /* reader/writer local variables elided */
  }
}
你可能会说,这并不是一件难事,但它造成了两个问题:

  • 这意味着我们有两个独立的实例负责阅读和写作资源;因此,我们班无法确定两者是否一致。同样,也无法确保在这两者之间正确管理状态
  • 作为调用者,我当然可以通过首先创建一个实例并为这两个参数传递它来避开这个问题。但这剥夺了我在一行中创建对象的能力,这看起来很奇怪
任何和我在一起这么久的人都会知道我现在要去哪里:)

优雅的解决方案是为支持读写的类型引入一个接口:

有了这个接口,我们的有问题的类型可以重写为

public class NeedsReadAndWrite{
  public NeedsReadAndWrite(IReadsAndWritesAResource readerWriter){
    /* local variable assignment elided */
  }
}
这两个问题现在都被回避了

同样,创建实现这个新接口的基本代理类型变得非常简单,方法是接收读写器实例,并将读/写调用转发给这些实例


我认为这个例子确切地说明了为什么您会,或者甚至应该,使用将两个或多个其他接口组合在一起的标记接口。

为什么我突然显示为“user123432”?这不是我在StackOverflow上的身份证。你有问题吗?无论如何,你可以访问以检查bug。结果是我的个人资料中的显示名被删除了。让我吃惊的是,我以前从未遇到过这种情况。被标记为已接受的答案,因为,虽然所有答案都是正确的,但从领域角度来看,这一点是肯定的。这在我的领域内确实是有意义的,如果我从这个角度考虑的话,答案是显而易见的。我建议,一个完全继承另一个接口的空接口可能是一件好事,也是一件有用的事情(尽管没有得到充分利用)。例如,我希望看到一些派生词if
IEnumerable
,有些是添加成员的,有些是不添加成员的。例如,
IMultipassEnumerable
应该从
IEnumerable
派生,并使用
Reset()
方法返回一个
IMultipassEnumerator
(不应该在
IEnumerator
中)
IImmutableEnumerable
应派生自
IMultipassEnumerable
,并且……不添加任何新成员,而是添加一个承诺,即
GetEnumerator
返回的所有枚举数将返回相同的
T
对象集(请注意,
T
对象本身可能是不变的,也可能不是不变的;承诺是枚举器将始终返回相同的对象集).Code将存储对IEnumerable的引用以存储内容的代码可以使用IImmutableEnumerable。是的,我可以肯定地看到其中的潜力,以及它的论据。但是,如果一个真正空的接口假定会承诺类似的内容,那么问题是没有办法执行一个类实现这个接口并不能保证它会玩fai
public class NeedsReadAndWrite{
  public NeedsReadAndWrite(IReadsAndWritesAResource readerWriter){
    /* local variable assignment elided */
  }
}