我读了一本书"通过C#第四版CLR".我无法理解一个陈述:
因此,例如,如果您有以下代码行:
Run Code Online (Sandbox Code Playgroud)FileStream[] fsArray;那么当CLR创建的
FileStream[]类型,它会导致这种类型的自动实现IEnumerable<FileStream>,ICollection<FileStream>以及IList<FileStream>接口.此外,该FileStream[]类型也将实现的接口的基本类型:IEnumerable<Stream>,IEnumerable<Object>,ICollection<Stream>,ICollection<Object>,IList<Stream>,和IList<Object>.
我用这段代码测试了这个语句:
FileStream[] fsArray = new FileStream[0];
string s = null;
foreach (var m in fsArray.GetType().GetInterfaces())
s += m.ToString() + Environment.NewLine;
Run Code Online (Sandbox Code Playgroud)
结果,我有这个:
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]
Run Code Online (Sandbox Code Playgroud)
没有执行IEnumerable<Stream>和其他人!我在某处弄错了吗?或杰弗里里希特犯了错误?
此外,我认为这是无意义的.因为Arrays支持协方差.
\n\n\n没有 IEnumerable 等的实现!
\n
没有。然而,IList<Stream> streamList = fsArray;会起作用的。您可以streamList按照您的预期使用,但如果您尝试在数组上执行无效的操作(只要该数组是从零开始的并且具有单个维度\xe2\x80\x94"SZ 数组,则会出现运行时异常) “用微软的说法\xe2\x80\x94否则是不允许的)。
想看到更糟糕的事情吗?
\n\nvar listMap = typeof(List<FileStream>).GetInterfaceMap(typeof(IList<FileStream>)); // This works fine.\nvar arrMap = typeof(typeof(FileStream[]).GetInterfaceMap(typeof(IList<FileStream>)); // This throws `ArgumentException`\nRun Code Online (Sandbox Code Playgroud)\n\n所以在这方面,FileStream[]甚至没有实施IList<FileStream>;如果确实如此,那么上面的行肯定应该起作用。
从 .NET 4.0 开始,我们得到了一个有趣的线索。在此之前,ArgumentException将有一条消息,与我们尝试打开该接口或 时"Interface not found"的消息相同。现在是[原文如此]intstring[]"Interface maps for generic interfaces on arrays cannot be retrived."
如果我们尝试获取接口映射IList<Stream>但不获取完全不受支持的接口(例如IList<bool>.
这里正在发生一些不寻常的事情。
\n\n它根本FileStream[]不直接支持任何通用接口,就像 aclass或struct一样。
相反,有一个名为的存根类SZArrayHelper,它在运行时为从零开始的一维数组提供这些接口。.NET Core 版本的评论内容丰富:
//----------------------------------------------------------------------------------------\n// ! READ THIS BEFORE YOU WORK ON THIS CLASS.\n// \n// The methods on this class must be written VERY carefully to avoid introducing security holes.\n// That\'s because they are invoked with special "this"! The "this" object\n// for all of these methods are not SZArrayHelper objects. Rather, they are of type U[]\n// where U[] is castable to T[]. No actual SZArrayHelper object is ever instantiated. Thus, you will\n// see a lot of expressions that cast "this" "T[]". \n//\n// This class is needed to allow an SZ array of type T[] to expose IList<T>,\n// IList<T.BaseType>, etc., etc. all the way up to IList<Object>. When the following call is\n// made:\n//\n// ((IList<T>) (new U[n])).SomeIListMethod()\n//\n// the interface stub dispatcher treats this as a special case, loads up SZArrayHelper,\n// finds the corresponding generic method (matched simply by method name), instantiates\n// it for type <T> and executes it. \n//\n// The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be\n// array that is castable to "T[]" (i.e. for primitivs and valuetypes, it will be exactly\n// "T[]" - for orefs, it may be a "U[]" where U derives from T.)\n//----------------------------------------------------------------------------------------\nRun Code Online (Sandbox Code Playgroud)\n\n这就是发生的事情。如果你尝试投射fsArray到,IList<Stream>那么你会让这个类为你做呼叫。如果您调用,GetInterfaces()您会得到类似的存根代码,仅提供与数组类型相关的代码。在任何一种情况下fsArray ,都class实现了您引用的书中提到的所有接口,但它的方式与 a或can不同struct。
(类比一下,anint既可以是 32 位值的四个字节,又可以是具有接口实现、方法覆盖等的“完整”对象)
所以这本书是正确的,但你也没有错过任何东西,因为当类型实现接口时我们期望发生的一些事情并没有发生。
\n\n\n\n\n此外,我认为这是没有意义的。因为数组支持协方差。
\n
支持协方差并不意味着它们将实现给定的接口,反之亦然。特别是因为数组(可以说是破碎的)协变与接口中的协变非常不同,并且早于它,并且实际上让数组实现通用接口也早于接口协变。
\n\n然而,决定确实FileStream[]应该实现确实Stream[]与协变数组有关(否则该决定将是非常奇怪的错误),但它需要SZArrayHelper提供的额外帮助,而不是自动包含它。
| 归档时间: |
|
| 查看次数: |
437 次 |
| 最近记录: |