有趣的是,当我在 Visual Studio 中查看 IList<T>
的定义时,它与 GitHub 上的源代码并不相同。
IList<T>
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
ICollection<T>
public interface ICollection<T> : IEnumerable<T>, IEnumerable
鉴于 ICollection<T>
已经包含 IEnumerable<T>
和 IEnumerable
,为什么 IList<T>
需要包含它们。不能简化成下面这样吗?
public interface IList<T> : ICollection<T>
我试图理解这个长接口链背后的逻辑。
您可以查看下面的源代码以查看差异。
答案 0 :(得分:17)
短版
在 .NET 中,接口不形成层次结构树。当一个类型实现一个派生接口时,它实现了所有的“父”接口。这是实际规范的一部分
长版
why does IList need to inherit from both of them
没有。 actual source for .NET Old in GitHub 是:
public interface IList<T> : ICollection<T>
public interface IList<T> : ICollection<T>
这个问题没有解释多重继承的假设从何而来。也许文档被误解了?
好的文档总是列出了一个类实现的所有接口。如果没有,程序员将不得不寻找多个链接来找出一个类做了什么、它实现了什么或专门的行为是什么。
事实上,2000 年左右的 COM 文档就是这样,将类和接口文档分开。那是在 Google 和在线文档出现之前,所以找出一个班级做了什么真的很难。找出需要实例化以获得特定服务的类几乎是不可能的。
Intellisense、参数信息、IDE 也显示所有实现的接口,因为
修改后
所以产生误解是因为代码中继承的接口被编译器扩展了。这段代码:
interface IX{}
interface IY:IX{}
public class C :IY{
public void M() {
}
}
changes into this in Sharplab.io :
public class C : IY, IX
{
public void M()
{
}
}
生成的 IL 显示了相同的内容:
.class public auto ansi beforefieldinit C
extends [System.Private.CoreLib]System.Object
implements IY,
IX
{
这说明从 IX
单独继承与从所有继承接口继承完全一样。
.NET 中的接口实际上就是一个接口。就像墙上插座是一个接口一样,或者一个 4 针音频插孔是一个接口。 4 针音频插孔“继承”了 1 个立体声和 1 个麦克风连接。立体声连接“继承”了 2 个单声道连接。
虽然我们没有看到 2 个引脚组,但我们看到并使用了 2 个单声道和 1 个麦克风引脚。
它在规范中
在 .NET 中,接口实际上是 API 规范,而不是实现。当一个类实现一个从其他类派生的接口时,它实现了所有这些接口。接口不像类那样形成层次树。
来自 the ECMA CIL standard 的 Interface Type Derivation
部分 (1.8.9.11)
为了突出最后一个区别,考虑一个接口 IFoo,它只有一个方法。派生自它的接口 IBar 要求任何支持 IBar 的对象类型也支持 IFoo。它没有说明 IBar 本身将具有哪些方法。
答案 1 :(得分:13)
TL;DR:编译器将编译该类,就好像它专门将所有提到的接口以及所有隐含/继承的接口实现到程序集中。如果不实际下载和显示原始源代码,ILSpy、ILDAsm 或“转到定义”就无法知道差异。
既然您现在已经阐明您在 Visual Studio 中使用了转到定义,那么范围内有两个工具:
两者都采用不同的方法来显示已编译程序集的内容。我相信 ILSpy 在 Visual Studio 的幕后使用,但请继续阅读为什么这并不重要。
如果我们在 LINQPad 中做一个简单的测试:
void Main()
{
}
public interface IA
{
}
public interface IB : IA
{
}
public class Test : IB
{
}
然后让 LINQPad 使用 ILSpy 反映代码,我们得到 Test
的定义:
public class Test: IB, IA
显然 ILSpy 显示 Test
实现了两者,而源只是通过 IA
获得 IB
。
ILDasm 怎么样?我使用 Visual Studio 编写了一个 .NET 5 程序集,然后使用 ILDasm 反编译它,代码与上面完全相同:
.class interface public abstract auto ansi ClassLibrary3.IA
{
} // end of class ClassLibrary3.IA
.class interface public abstract auto ansi ClassLibrary3.IB
implements ClassLibrary3.IA
{
} // end of class ClassLibrary3.IB
.class public auto ansi beforefieldinit ClassLibrary3.Test
extends [System.Runtime]System.Object
implements ClassLibrary3.IB,
ClassLibrary3.IA
{
基本上,这是编译器如何编译源代码的工件。我没有足够的 IL 知道是否从中级语言重新组装界面,没有提到 IA
实际上会产生相同的输出,但我会将其作为练习。
我还查看了此信息的各种来源:
IList
没有,但 for IList<T>