我正在经过Jon Skeet的Edulinq,我遇到了以下代码,第23页,他为Linq的Empty()
运算符实现了缓存机制
private static class EmptyHolder<T>
{
internal static readonly T[] Array = new T[0];
}
我的问题是,这实际上如何缓存Array
变量?
可选地,它如何在CLR中起作用?
编辑:在此之后,他提到了反对返回数组的反抗。为什么有人不返回一个数组(即使它是0大小?)?
答案 0 :(得分:14)
我的问题是,这实际上如何缓存Array变量?
CLR按类型参数缓存它。基本上,EmptyHolder<int>
是与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大小?)?
嗯,有评论:
数组方法不是很好:人们将错误地依赖返回值作为数组,尽管没有记录。
我个人认为这不是一个问题,但编写替代实现很有趣:)
答案 1 :(得分: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一样,这是一个值得关注的小优化。