C# 阵列中自动实现的接口
我读了一本书“CLR通过C#第四版”。我无法理解一种说法: 例如,如果您有以下代码行:C# 阵列中自动实现的接口,c#,clr,C#,Clr,我读了一本书“CLR通过C#第四版”。我无法理解一种说法: 例如,如果您有以下代码行: FileStream[] fsArray; 然后,当CLR创建FileStream[]类型时,它将 使此类型自动实现 IEnumerable,ICollection,以及 IList接口。此外,FileStream[]类型 还将实现基本类型的接口: IEnumerable,IEnumerable, ICollection,ICollection, IList,和IList 我用以下代码测试了此语句: Fil
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]`@NikhilAgrawalIList
在书中;这本书的正文继续断言“基本类型的接口…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