为什么CLR重用空字符串,而不是空数组?

  • 本文关键字:数组 字符串 CLR .net clr
  • 更新时间 :
  • 英文 :

我注意到
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不这样做?我是不是漏掉了什么?

字符串可以使用实习,这使得它们(与所有其他类型的对象)是不同的。

数组本质上就是对象。在语法或上下文不清楚的情况下重用实例并非没有副作用或风险。

static int[] empty = new int[0];
...
   lock (empty) { ... }

如果其他代码锁定了另一个(他们认为)空的int[],你可能会有一个死锁,这是很难发现的。

其他场景包括使用数组作为Dictionary中的键,或其他任何与其标识相关的地方。框架不能只是改变规则。

使用"new"创建对象将始终创建一个新实例,该实例可能与任何其他实例被锁定,并且ReferenceEquals将报告其与所有其他实例不同。如果有系统定义的工厂方法或属性来创建空数组,类似于Enumerable空或字符串。如果属性为空,则可以返回共享对象实例,但是暴露的构造函数除了返回新实例或抛出异常之外不能做任何事情。

最新更新