自动实现的接口数组中 [英] Auto implemented interfaces in Arrays

查看:114
本文介绍了自动实现的接口数组中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读通过C#第四版CLR一书。我无法理解一个语句:




因此,举例来说,如果你有下面的代码行:

 的FileStream [] fsArray;当CLR创建的FileStream []   



然后>类型,它将
导致这种类型的自动执行
的IEnumerable<的FileStream> 的ICollection<的FileStream> ,和
的IList<&的FileStream GT; 接口。此外,的FileStream [] 键入
也将实现的接口为基本类型:
的IEnumerable<流> 的IEnumerable<对象>
的ICollection<流> 的ICollection<对象>
的IList<流> 的IList<对象>




我测试了这一说法与此代码:

 的FileStream [] = fsArray新的FileStream [0]; 

字符串s = NULL;
的foreach(在fsArray.GetType变种M()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<流>流列表= fsArray; 将工作。您还可以使用流列表如你所期望,虽然是运行时异常,如果你试图做一个阵列上无效的东西(只要数组是零基础,在微软的说法,否则是不允许有一个单一的无量纲SZ阵列)。



想看到更坏的东西?

  VAR列表地图= typeof运算(名单<&的FileStream GT;)GetInterfaceMap。(typeof运算(IList的<&的FileStream GT;)); //这工作得很好。 
VAR arrMap = typeof运算(typeof运算(的FileStream [])GetInterfaceMap(typeof运算(IList的<的FileStream>)); //这会引发`ArgumentException`

所以在这方面,的FileStream [] 甚至不落实的IList<的FileStream> ;如果是的话那么肯定是上面的行应该工作



我们得到一个有趣的线索的.NET 4.0在此之前,在<。 code>的ArgumentException 将有一个消息界面找不到,同样因为它会如果我们想设法得到在 INT 的String [] ,现在是的通用接口接口映射接口数组不能retrived。 [原文]



和它也给我们这一点,如果我们试图让接口映射为的IList<流> 而不是像的IList℃的完全不支持的接口;布尔方式>



某种不寻常的发生在这里。



和它是什么,就是的FileStream [] 不直接支持任何通用接口可言,以同样的方式,一个结构会。



相反,有 SZArrayHelper 称为存根类在运行时从零开始的一维数组提供这些接口。在 .NET Core版本<注释/ A>是资料:

  // ------------------ -------------------------------------------------- -------------------- 
//!阅读此之前你工作这个类。
//
//这个类中的方法必须非常小心地写到避免引入安全漏洞。
//这是因为他们被调用的特殊本! 此对象
//所有这些方法都不是SZArrayHelper对象。相反,它们是U型[]
//其中U []是强制转换为T []的。没有实际SZArrayHelper对象已经被实例化。因此,你将
//看到了很多投这个的T []的表情。
//
//需要这个类,允许类的SZ数组T []揭露的IList< T> ;,
//的IList< T.BaseType>等,等,一路攀升到IList<对象> ;.当下面的调用是
//做:
//
//((IList的< T>)(新U [N]))SomeIListMethod()
//
//接口存根调度员将此视为一个特殊的情况下,负载高达SZArrayHelper,
//找到相应的通用法(方法的名称简单匹配),实例化
//它的类型< T>并执行。
//
//的T将反映用来调用该方法的接口。实际运行时间这个将是
//数组,它是可浇注为T [](即对primitivs和值类型,这将是准确
//T [] - 为orefs,它可能是一个U []其中U从T.派生)
// ---------------------------- -------------------------------------------------- ----------

这就是发生了什么。如果您尝试投 fsArray 的IList<流> 那么你得到这个类为你做的呼吁。如果你调用 GetInterfaces()你会得到类似的存根代码只提供那些与数组的类型。在这两种情况下, fsArray 确实实现你引用书中提到的所有接口,但它不会做它以同样的方式作为一个结构即可。



(考虑对类比如何一个 INT 既可以是四个字节的32位值,也是一个完全的对象与接口实现,方法覆盖等。)



所以,这本书是正确的,但你是不是缺少什么不是,因为有些我们预计当一个类型实现的接口没有发生的事情。




此外,我认为这是平均值少。由于阵列支持协方差。




支持协方差并不意味着他们将实现给定的接口,反之亦然。特别是由于阵列(可以说打破)协方差是接口的有很大不同,而且早了一下,确实有数组实现通用接口还早接口协方差。



不过,这决定了的FileStream [] 的确应该落实流[] 确实涉及到数组是协变(该决定将一直只是奇怪的是错的,否则),但它需要额外的帮助, SZArrayHelper 提供的,而不是被它会自动承担的责任。


I read a book "CLR via C# Fourth Edition". And I cannot understand one statement:

So, for example, if you have the following line of code:

FileStream[] fsArray;

then when the CLR creates the FileStream[] type, it will cause this type to automatically implement the IEnumerable<FileStream>, ICollection<FileStream>, and IList<FileStream> interfaces. Furthermore, the FileStream[] type will also implement the interfaces for the base types: IEnumerable<Stream>, IEnumerable<Object>, ICollection<Stream>, ICollection<Object>, IList<Stream>, and IList<Object>.

I tested this statement with this code:

FileStream[] fsArray = new FileStream[0];

string s = null;
foreach (var m in fsArray.GetType().GetInterfaces())
    s += m.ToString() + Environment.NewLine;

and as a result, I have this:

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]

There is no implementation of IEnumerable<Stream> and others! Did I make mistake somewhere? Or did Jeffrey Richter make mistake?

Furthermore, I think it is mean-less. Because Arrays support co-variance.

解决方案

There is no implementation of IEnumerable and others!

Nope. And yet, IList<Stream> streamList = fsArray; will work. And you can use streamList as you'd expect, though with runtime exceptions if you try to do something not valid on an array (as long as the array is zero-based and has a single dimension—"SZ arrays" in Microsoft parlance—otherwise it's not allowed).

Want to see something worse?

var listMap = typeof(List<FileStream>).GetInterfaceMap(typeof(IList<FileStream>)); // This works fine.
var arrMap = typeof(typeof(FileStream[]).GetInterfaceMap(typeof(IList<FileStream>)); // This throws `ArgumentException`

So in this regard, FileStream[] doesn't even implement IList<FileStream>; if it does then surely the above line should work.

We get an interesting clue as of .NET 4.0. Prior to that, the ArgumentException would have a message of "Interface not found", the same as it would if we'd tried to get that interface on int or string[]. Now it is "Interface maps for generic interfaces on arrays cannot be retrived." [sic]

And it also give us this if we try to get the interface map for IList<Stream> but not for a completely unsupported interface like IList<bool>.

Something unusual is happening here.

And what it is, is that FileStream[] does not directly support any generic interface at all, in the same way that a class or struct would.

Instead there is a stub class called SZArrayHelper which provides these interfaces at runtime for zero-based one-dimension arrays. The comment on the .NET Core Version is informative:

//----------------------------------------------------------------------------------------
// ! READ THIS BEFORE YOU WORK ON THIS CLASS.
// 
// The methods on this class must be written VERY carefully to avoid introducing security holes.
// That's because they are invoked with special "this"! The "this" object
// for all of these methods are not SZArrayHelper objects. Rather, they are of type U[]
// where U[] is castable to T[]. No actual SZArrayHelper object is ever instantiated. Thus, you will
// see a lot of expressions that cast "this" "T[]". 
//
// This class is needed to allow an SZ array of type T[] to expose IList<T>,
// IList<T.BaseType>, etc., etc. all the way up to IList<Object>. When the following call is
// made:
//
//   ((IList<T>) (new U[n])).SomeIListMethod()
//
// the interface stub dispatcher treats this as a special case, loads up SZArrayHelper,
// finds the corresponding generic method (matched simply by method name), instantiates
// it for type <T> and executes it. 
//
// The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be
// array that is castable to "T[]" (i.e. for primitivs and valuetypes, it will be exactly
// "T[]" - for orefs, it may be a "U[]" where U derives from T.)
//----------------------------------------------------------------------------------------

And that's what happens. If you try to cast fsArray to IList<Stream> then you get this class doing the calls for you. If you call GetInterfaces() you get similar stub code providing just those related to the type of the array. In either case fsArray does implement all the interfaces mentioned in the book you quote, but it doesn't do it in the same way as a class or struct can.

(Consider for analogy how an int can be both four bytes of the 32-bit value and also a "full" object with interface implementations, method overrides, etc.)

So the book is correct, but you aren't missing anything either, because some of the things we'd expect to happen when a type implements an interface don't.

Furthermore, I think it is mean-less. Because Arrays support co-variance.

Supporting co-variance does not mean they'll implement a given interface, or vice-versa. Especially since arrays' (arguably broken) covariance is very different to that in interfaces, and predates it, and indeed having arrays implement generic interfaces also predates interface covariance.

However, that it was decided that FileStream[] should indeed implement Stream[] does relate to arrays being covariant (the decision would have been just bizarrely wrong otherwise), but it needs the extra help that SZArrayHelper provides, rather than being automatically entailed by it.

这篇关于自动实现的接口数组中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆