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

发布于 2024-12-11 23:08:46 字数 1048 浏览 0 评论 0原文

我注意到

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(),我们发现它缓存并重用空数组:

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() 的调用,还适用于 new T[0 ]。如果 Enumerable.Empty() 中的优化值得,那么这肯定更值得吗?

为什么 CLR 不这样做?我有什么遗漏的吗?

I notice that

Console.WriteLine((object) new string(' ', 0) == (object) new string(' ', 0));

prints true, which indicates that the CLR keeps the empty string around and re-uses the same instance. (It prints false for any other number than 0.)

However, the same is not true for arrays:

Console.WriteLine(new int[0] == new int[0]);   // False

Now, if we look at the implementation of Enumerable.Empty<T>(), we find that it caches and re-uses empty arrays:

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;
    }
}

So the framework team felt that keeping an empty array around for every type is worth it. The CLR could, if it wanted to, go a small step further and do this natively so it applies not only to calls to Enumerable.Empty<T>() but also new T[0]. If the optimisation in Enumerable.Empty<T>() is worth it, surely this would be even more worth it?

Why does the CLR not do this? Is there something I’m missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我爱人 2024-12-18 23:08:46

字符串可以使用实习,这使它们成为一个不同的故事(与所有其他类型的对象)。

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

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

如果其他一些代码锁定了另一个(他们认为)空的int[],那么您可能会遇到很难发现的死锁。

其他场景包括使用数组作为字典中的键,或者它们的身份重要的任何其他地方。框架不能只是改变规则。

Strings may use interning, that makes them a different story (from all other kind of objects).

Arrays are essentially just objects. Re-using instances where that is not clear from the syntax or context isn't without side effects or risks.

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

If some other code locked on another (they thought) empty int[] you might have a deadlock that is very hard to find.

Other scenarios include using arrays as the key in a Dictionary, or anywhere else their identity matters. The framework can't just go around changing the rules.

笛声青案梦长安 2024-12-18 23:08:46

使用“new”创建对象将始终创建一个新实例,该实例可能与任何其他实例不同地被锁定,并且 ReferenceEquals 将报告为与所有其他实例不同。如果有系统定义的工厂方法或属性来创建空数组,类似于 Enumerable.Empty 或 String.Empty,这些属性可以返回共享对象实例,但公开的构造函数除了返回新实例或抛出异常之外不能执行任何操作一个例外。

Creating an object with "new" will always create a new instance, which may be locked distinctly from any other instance, and which ReferenceEquals will report as distinct from all other instances. If there were system-defined factory methods or properties to create empty arrays, similar to Enumerable<T>.Empty or String.Empty, those properties could return shared object instances, but exposed constructors cannot do anything other than return a new instance or throw an exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文