用于IList <t>,IEnumerable <t>和ICollection <t>的TypeDependencyAttribute(“System.SZArrayHelper”)的用途?

时间:2015-11-10 14:16:58

标签: c# .net

IList,IEnumerable和ICollection的source code中提供的评论说

  

请注意T[] : IList<T>,我们希望确保您使用    IList<YourValueType>,我们确保可以使用YourValueType[]    没有jitting。因此TypeDependencyAttributeSZArrayHelper。    这在内部是一个特殊的黑客 - 请参阅VM \ compile.cpp。

为什么IList<T>包含对SZArrayHelper的依赖?我理解SZArrayHelper是一个实现IList<T>接口的数组的CLR包装器,但我不能全面了解为什么这两个被绑在一起。

如果没有jitting,它如何确保YourValueType[]可以使用。

1 个答案:

答案 0 :(得分:10)

正如你的引言中所述,这是JIT中的一个黑客攻击。当VM发现TypeDependency上有SZArrayHelper时,它会以不同的方式处理该类,从而允许使用更高效的代码。

查看VM中的相关代码(请注意,我在这里使用较旧的公共版本 - 而不是实际的 .NET VM):

  

必须特别处理通过IList(或IEnumerable或ICollection)调用数组。   这些界面是“神奇的”(主要是由于工作集有关 - 它们是在内部按需创建的   即使在语义上,这些都是静态接口。)

首先,数组在.NET中是一个黑客攻击。添加通用接口时,这会产生一些问题 - 例如,int[]Array,但它也是一个特殊类型,而int数组;在添加真正的泛型类型之前,这允许数组是通用的。

现在,让我们看一个具体的例子。你有一个int[],你想在LINQ中使用它。由于int[]实现了IEnumerable<int>,它为您提供了开箱即用的LINQ的全部功能,您可以编写如下内容:

var positiveNumbers = numbers.Where(i => i > 0);

从C#的角度来看,没有问题。但是,从VM的内部角度来看,这个 是一个很大的问题,因为int[] 实际上实现IEnumerable<int>!即使在将泛型引入.NET(和C#)之后,数组仍然以旧的方式处理。

hack是使用SZArrayHelper来处理任何这些泛型方法。因此,例如,WhereGetEnumerator内部调用IEnumerable<int>。虚拟机发现您正在尝试在阵列上调用GetEnumerator,而不是在数组实例上虚拟调度GetEnumerator,而是将调用重定向到SZArrayHelper.GetEnumerator<int>()

这是一个巨大的黑客 - 如果你查看SZArrayHelper的参考代码,你会发现大量的警告 - 例如,GetEnumerator<int>方法是一个实例方法,但它的this参数实际上是数组(例如int[]),而不是SZArrayHelper

但它允许我们将数组视为实际实现所有这些通用接口 - 即使它们没有:)