8

我正在浏览 Jon Skeet 的 Edulinq,我遇到了以下代码,第 23 页,他在其中Empty()为 Linq 的运算符实现了缓存机制

private static class EmptyHolder<T>
{
   internal static readonly T[] Array = new T[0];
}

我的问题是,这实际上是如何缓存Array变量的?

(可选)它如何在 CLR 中工作?

编辑:同样在此之后,他提到了对返回数组的反抗。为什么任何人都不应该返回一个数组(即使它的大小为 0?)?

4

2 回答 2

13

我的问题是,这实际上是如何缓存 Array 变量的?

CLR 按类型参数缓存它。基本上,EmptyHolder<int>是与 etc 不同的类型,并且每个具体EmptyHolder<string>类型都会调用一次类型初始化程序(由 CLR 自动调用)。

所以:

var x = EmptyHolder<string>.Array; // Needs to construct the empty string[] array
var y = EmptyHolder<string>.Array; // No extra work! x and y have the same value
var z = EmptyHolder<int>.Array; // This constructs an empty array for int[]

(可选)它如何在 CLR 中工作?

恐怕这是一个我不太了解的实现细节。但基本上这都是关于 CLR 如何做事的:)

编辑:同样在此之后,他提到了对返回数组的反抗。为什么任何人都不应该返回一个数组(即使它的大小为 0?)?

嗯,有评论说:

数组方法不是很好:人们会错误地依赖返回值是一个数组,尽管这没有记录。

我个人认为这不是问题,但编写替代实现很有趣:)

于 2014-01-07T17:51:33.767 回答
0

每次为 T 首次调用 EmptyHolder.Empty() 时,都必须为 EmptyHolder 调用静态构造函数。

现在看起来好像没有静态构造函数了,对吧?错误的。该类可以重写为...

private static class EmptyHolder<T>
{
   static EmptyHolder<T>()
   {
       Array = new T[0];
   }
   internal static readonly T[] Array;

   public IEnum<T> Empty();
}

现在, Empty 的后续运行将不会调用静态构造函数(除非使用不同的 T)。

尽管我可能会批评 Jon Skeet,但这是一个需要担心的微小优化。

于 2013-02-06T16:29:13.137 回答