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