新对象[] {} vs Array.Empty<object>()

54
当我输入以下代码时:
object[] objects = new object[] { };

Visual Studio 告诉我:

避免不必要的零长度分配。 使用 Array.Empty<object>() 代替。

使用它们之一是否有任何实际影响?

为什么会出现这个警告?


4
每次调用Array.Empty()都会返回同一个数组,而你的代码会创建多个数组。这可能是为了避免不必要的开销。 - user47589
4
你正在创建一个不必要的东西。Array.Empty 引用了一个静态只读属性,因此在应用程序域中只有一个实例。 - user1228
@Will 请把那个作为答案。 - Mike Cheel
4
如果 Visual Studio 能够检测到并生成警告,为什么编译器不能进行修复? - Joe
2
@Joe 我猜这种情况可能会出现,当你需要多个空数组时。 - Mike Cheel
显示剩余3条评论
2个回答

83
你正在创建一个空数组。由于无法更改数组实例的容量(说不能更改其长度听起来很奇怪,我不知道为什么),因此它将始终为空。每次这样做,您都会创建另一个永远无法使用的数组实例。频繁这样做可能会导致浪费GC和内存压力,从而引发警告。
相反,不要创建空数组,只需使用建议的Array.Empty<T>()即可。该方法返回使用此静态类的数组。
internal static class EmptyArray<T>
{
    public readonly static T[] Value;

    static EmptyArray()
    {
        EmptyArray<T>.Value = new T[0];
    }
}

由于这个数组是“静态的”和“只读的”,所以在整个应用程序域中只有一个实例。空数组本质上是不可变的,因此缓存该实例并不成问题。如果你发现正在创建大量的空数组并且想要避免特殊处理空数组的创建,那么它可以让你跳过这个步骤并找到一种更加优美的代码路径。 Enumerable.Empty<T>() 是用于 Linq to Objects 的等效语法,同时也适用于不浪费内存分配来创建空对象的情况。

2
这很有趣!我没有意识到这个类是staticreadonly的,它只会创建一个空数组的实例…让我想到了我们团队一直在处理的巨型应用程序内部潜在问题。遗憾的是,Visual Studio没有为其修复提供解释。 - Niklas

9

使用Array.Empty可以避免不必要的内存分配。

请参考下面来自.NET库的代码:

[Pure]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static T[] Empty<T>()
{
    Contract.Ensures(Contract.Result<T[]>() != null);
    Contract.Ensures(Contract.Result<T[]>().Length == 0);
    Contract.EndContractBlock();

    return EmptyArray<T>.Value;
}
...
// Useful in number of places that return an empty byte array to avoid unnecessary memory allocation.
internal static class EmptyArray<T>
{
    public static readonly T[] Value = new T[0];
}

来源:https://referencesource.microsoft.com/#mscorlib/system/array.cs,bc9fd1be0e4f4e70

这是一个指向微软参考源代码的链接,其中包含有关数组类的信息。

我想在Code Contracts上添加评论,因为它们不支持.NET 5+(https://learn.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts)。 - GLJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接