为什么接口不能包含类型?

问题描述 投票:9回答:5

这在C#中吸引了我一到两次。我可以编写这样的代码

class Node
{
    class Connection
    {
        public Connection(Node node, string label)
        {
            this.Node = node;
            this.Label = label;
        }
        public Node Node { get; private set;  }
        public string Label { get; private set; }            
    };

    IEnumerable<Connection> IncomingConnections() // ...
    IEnumerable<Connection> OutgoingConnections() // ...
}

但是如果我写

interface INode
{
    class Connection
    {
        public Connection(INode node, string label)
        {
            this.Node = node;
            this.Label = label;
        }
        public INode Node { get; private set; }
        public string Label { get; private set; }
    };

    IEnumerable<Connection> IncomingConnections();
    IEnumerable<Connection> OutgoingConnections();
}

我收到编译错误

错误CS0524:'连接':接口无法声明类型

我了解限制,但我感兴趣的是why。我当然可以在C ++“接口”(这只是一个具有抽象成员的类,因此不足为奇)中具有嵌套类型,并且显然在Java中也是可能的,请参见Interfaces Cannot Declare Type Issue C#。因此,鉴于C#从Java中学到了一些东西,为什么在这方面缺少它(如果确实缺少)?

(很抱歉,如果已经在其他地方解决了这个问题。我也找到了Interfaces cannot declare typesWhy can't I put a delegate in an interface?,但它们似乎并没有直接解决我的问题。]

编辑

我以为我只是想添加一个注释,以说在Java世界中,乍一看似乎是一个关于在接口内嵌套类是否可以的问题。参见https://stackoverflow.com/a/9098321/834521。我认为我在问为什么同样的不适用于C#并不是很愚蠢。

编辑

Framework Design Guidelines的摘要/引用,第二版,第4.9页115-117。

  • Do use嵌套类型,例如嵌套类型需要访问封闭类型的私有成员。
  • 不使用公共嵌套类型进行分组;为此使用名称空间。
  • Avoid公开嵌套的类型,除非您真的知道自己在做什么。 (主要动机:显式创建嵌套类型会使技术水平较低的开发人员感到困惑。但是,例如通过集合枚举器隐式创建是可以的。)
  • [不使用嵌套类型,如果要在包含类型之外使用或实例化嵌套类型(这两者都主张嵌套类型与包含类型的独立性)。
  • 不要用作接口的成员。
c#
5个回答
31
投票

为什么接口不能包含类型?

在深入探讨问题之前,我先澄清几件事。

首先,CLR类型系统允许在接口内部使用嵌套类型。完全有可能创建C#或VB版本,或者将来在接口内部声明支持接口,委托,类,结构和枚举的任何版本,并且它将在现有CLR上运行。

[其次,我将以“为什么C#语言不实现功能X的形式?对于X的所有值,答案都是相同的。要实现该功能,必须做到:考虑,设计,指定,实现,测试并交付给客户。如果这六件事中的任何一件事没有发生,那么就没有任何功能。 未实现功能X,因为其中一项或多项未发生。

第三,C#编译器团队(我不再关注)不必为not实现功能提供任何解释。功能部件要花钱,预算是有限的,因此要求功能部件的人有责任证明其优势与成本成正比。

第四,“为什么”的问题很难回答,而“为什么不”的问题甚至更难。

因此,我将拒绝您的问题,并将其替换为我可以回答的问题:

假设此功能请求已提交给C#设计团队。您对此有何反对意见?

  • 该功能虽然在CLR中合法,但在CLS中不合法。 C#中有很多功能在CLS中是不合法的,但是由于CLS指南专门是不要在接口中嵌套类型,因为大多数语言不支持它,因此在C#中实现该功能实质上是在鼓励人们编写其他语言无法使用的库。 建议的功能会鼓励不良的编程习惯

  • 嵌套类型给您带来三个主要优点。首先,他们可以访问其封闭类型的私有成员。这对于没有私有成员的接口没有好处。其次,它们提供了一种方便的方式来包含外部类型的特定私有实现细节。这对于接口可能没有好处,因为接口可能没有私有的嵌套类型,并且根据定义没有实现细节。第三,它们提供了一种将一种类型与另一种类型关联的便捷方法。但是,最好通过名称空间来完成。

  • 据我所知,没有其他人正在请求该功能。当有很多客户想要的功能时,不要花钱购买几乎没人想要的功能。

  • 实施此功能并不能使语言本身具有更强大的功能或更具表现力。

  • 实施此功能并不是我所知道的一些更出色的功能的垫脚石。该功能不与任何其他“主题”绑定。这是一种“完成主义”功能,可以消除小的非正交性,而不是有用的功能。

  • 对于缺少此功能,有一个简单的解决方法;只需将嵌套类型设为顶级类型即可。

是这种情况against。如果没有人提出有关该功能的案例,那么在设计委员会会议上,它的持续时间可能不会超过五分钟。您是否愿意为此功能提出理由?


2
投票
只有几个原因使嵌套类型有意义。主要原因是将它们定义为私有,以便只有容器类可以访问它们。容器类将在其自己的实现中使用这些私有类型。

1
投票
根据C#规范,第13.2节:

1
投票
尽管在这篇文章的评论中已提到它,但我想在此重申,您可以使用VB.Net创建具有嵌套类型的接口,然后使用该接口及其在C#中不受限制的所有嵌套类型。另外,您可以使用ILDasm或ILSpy之类的工具将该代码导出到IL,然后使用Visual Studio ILSupport扩展将其织回到您的库中(前提是您实际上并不需要直接在库中使用它。)>

由于某些人可能要这样做的原因,这里有两个。首先是为一组耦合接口提供蓝图/模式定义,这些接口具有支持通用概念(例如实体管理)所需的共享通用类型参数。例如:


0
投票
想补充一点,从C#8.0开始,允许接口使用嵌套类型。
© www.soinside.com 2019 - 2024. All rights reserved.