【发布时间】:2011-10-27 12:13:42
【问题描述】:
我注意到了
Console.WriteLine((object) new string(' ', 0) == (object) new string(' ', 0));
打印true,这表明CLR 保留空字符串并重新使用相同的实例。 (对于0 以外的任何其他数字,它都会打印false。)
但是,数组却不是这样:
Console.WriteLine(new int[0] == new int[0]); // False
现在,如果我们查看Enumerable.Empty<T>() 的实现,我们会发现它缓存并重用了空数组:
public static IEnumerable<TResult> Empty<TResult>()
{
return EmptyEnumerable<TResult>.Instance;
}
[...]
public static IEnumerable<TElement> Instance
{
get
{
if (EmptyEnumerable<TElement>.instance == null)
EmptyEnumerable<TElement>.instance = new TElement[0];
return EmptyEnumerable<TElement>.instance;
}
}
因此,框架团队认为为每种类型保留一个空数组是值得的。如果 CLR 愿意,它可以更进一步并在本机上执行此操作,因此它不仅适用于对 Enumerable.Empty<T>() 的调用,还适用于对 new T[0] 的调用。如果Enumerable.Empty<T>() 的优化值得,那肯定更值得?
为什么 CLR 不这样做?我有什么遗漏吗?
【问题讨论】:
-
我认为最大的异常是
new string(...)可以返回一个现有的引用,而不是它不能用于数组。这对我来说总是很奇怪。 -
@sll 基本数组不能添加或删除项目。一旦确定尺寸,它们的尺寸就很好了。
-
@Timwi:该行为违反了 C# 语言规范。来自第 7.6.10 节:“new 运算符用于创建类型的新实例。”和“new 运算符意味着创建一个类型的实例。” (可能还有更多我可以引用的例子。)同时检查是否违反了 ECMA-335...
-
FWIW,你会经常在我的代码中发现
private static readonly SomeType[] nix = new SomeType[0];;p -
@Timwi:在我看来,它违反了 ECMA-335 分区 III 的第 4.21 节:“newobj 指令创建了一个新对象或值类型的新实例。”显然这里没有这样做。