C# 阵列中自动实现的接口

C# 阵列中自动实现的接口,c#,clr,C#,Clr,我读了一本书“CLR通过C#第四版”。我无法理解一种说法: 例如,如果您有以下代码行: FileStream[] fsArray; 然后,当CLR创建FileStream[]类型时,它将 使此类型自动实现 IEnumerable,ICollection,以及 IList接口。此外,FileStream[]类型 还将实现基本类型的接口: IEnumerable,IEnumerable, ICollection,ICollection, IList,和IList 我用以下代码测试了此语句: Fil

我读了一本书“CLR通过C#第四版”。我无法理解一种说法:

例如,如果您有以下代码行:

FileStream[] fsArray;
然后,当CLR创建
FileStream[]
类型时,它将 使此类型自动实现
IEnumerable
ICollection
,以及
IList
接口。此外,
FileStream[]
类型 还将实现基本类型的接口:
IEnumerable
IEnumerable
ICollection
ICollection
IList
,和
IList

我用以下代码测试了此语句:

FileStream[] fsArray = new FileStream[0];

string s = null;
foreach (var m in fsArray.GetType().GetInterfaces())
    s += m.ToString() + Environment.NewLine;
因此,我有:

System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.IO.FileStream]
System.Collections.Generic.ICollection`1[System.IO.FileStream]
System.Collections.Generic.IEnumerable`1[System.IO.FileStream]
System.Collections.Generic.IReadOnlyList`1[System.IO.FileStream]
System.Collections.Generic.IReadOnlyCollection`1[System.IO.FileStream]
没有实现
IEnumerable
和其他功能! 我在什么地方出错了吗?还是杰弗里·里克特犯了错误

此外,我认为这意味着更少。因为数组支持协方差

没有IEnumerable和其他的实现

没有。然而,
IList streamList=fsArray将起作用。您可以按照预期使用
streamList
,但如果您试图在数组上执行无效操作(只要该数组是基于零的,并且在Microsoft术语中只有一个维度--“SZ数组”,否则不允许),则运行时会出现异常

想看看更糟的吗

var listMap = typeof(List<FileStream>).GetInterfaceMap(typeof(IList<FileStream>)); // This works fine.
var arrMap = typeof(typeof(FileStream[]).GetInterfaceMap(typeof(IList<FileStream>)); // This throws `ArgumentException`
事情就是这样。如果您尝试将
fsArray
强制转换为
IList
,则该类将为您执行调用。如果调用
GetInterfaces()
,则会得到类似的存根代码,只提供与数组类型相关的存根代码。在这两种情况下,
fsArray
都实现了您引用的书中提到的所有接口,但它的实现方式与
类或
结构不同

(为了进行类比,请考虑
int
如何既可以是32位值的四个字节,也可以是具有接口实现、方法重写等的“完整”对象。)

因此,这本书是正确的,但是您也没有遗漏任何东西,因为当一个类型实现一个接口时,我们期望发生的一些事情没有遗漏

此外,我认为这意味着更少。因为数组支持协方差

支持协方差并不意味着它们将实现给定的接口,反之亦然。特别是因为数组(可以说是破碎的)协方差与接口中的协方差非常不同,并且早于接口中的协方差,实际上,让数组实现通用接口也早于接口协方差

然而,决定
FileStream[]
确实应该实现
Stream[]
确实与协变数组有关(否则这个决定就错得离奇了),但它需要
szarayHelper
提供的额外帮助,而不是它自动带来的帮助

因为数组支持协方差

因为数组是协变的,所以它们还必须实现元素基类的通用接口。换言之,每个人都希望这能奏效:

    var a = new FileStream[] { new FileStream("a", FileMode.Create) };
    Stream[] b = a;                 // Fine, covariant
    var iterb = (IList<Stream>)b;   // Fine of course, actually iterates FileStreams
var a=newfilestream[]{newfilestream(“a”,FileMode.Create)};
流[]b=a;//好的,协变的
var iterb=(IList)b;//当然可以,实际上是迭代文件流
对Stream[]对象引用的赋值不会以任何方式改变对象,它仍然是一个隐藏的FileStream[]。所以这里的硬需求是FileStream[]还实现了
IList
。和
IList
。和
IEnumerable
,等等


所以你真正发现的是反射并不能完全模拟阵列协方差。这是可以原谅的。数组实际上并没有实现这些接口,CLR只知道如何提供具有所需行为的替换对象。像鸭子一样的庸医打字。有关此行为的更多信息,请参见。

您有
System.Collections.Generic.IList
1[System.IO.FileStream]`@NikhilAgrawal
IList
在书中;这本书的正文继续断言“基本类型的接口…
IEnumerable
”也应该存在,这显然是不正确的。提交勘误表,whydoncha
    var a = new FileStream[] { new FileStream("a", FileMode.Create) };
    Stream[] b = a;                 // Fine, covariant
    var iterb = (IList<Stream>)b;   // Fine of course, actually iterates FileStreams