C# 空数组初始化中的性能差异

C# 空数组初始化中的性能差异,c#,.net,arrays,performance,clr,C#,.net,Arrays,Performance,Clr,最近,我一直在从事性能/内存优化工作,并研究了空数组初始化,它使用通用方法初始化空数组: 通用空数组类的代码实现: public static class EmptyArray<T> { public static readonly T[] Instance; static EmptyArray() { Instance = new T[0]; } } var empt

最近,我一直在从事性能/内存优化工作,并研究了空数组初始化,它使用通用方法初始化空数组:

通用空数组类的代码实现:

    public static class EmptyArray<T>
    {
        public static readonly T[] Instance;

        static EmptyArray()
        {
            Instance = new T[0];
        }
    }
var emptyStrArr = EmptyArray<string>.Instance;
var emptyFooArr = EmptyArray<Foo>.Instance;
var emptyBarArr = EmptyArray<Bar>.Instance;
我已向上述代码作者询问,他已回复我:

基本上,所有空数组都是只读的,并且等于一个 另一个,这意味着您可以使用相同的实例(将 在运行时根据需要延迟创建)…这将减少 分配总数,减少内存使用和GC压力,以及 应该会有一些改善

尽管如此,我仍然无法理解
EmptyArray
实例如何提高数组声明中的性能

使用以下方法的代码是否存在性能差异:

第一次进近:

    public static class EmptyArray<T>
    {
        public static readonly T[] Instance;

        static EmptyArray()
        {
            Instance = new T[0];
        }
    }
var emptyStrArr = EmptyArray<string>.Instance;
var emptyFooArr = EmptyArray<Foo>.Instance;
var emptyBarArr = EmptyArray<Bar>.Instance;

在第一个代码中,
静态
构造函数只执行一次。因此,您只需创建一个数组并一直使用它。在第二段代码中,每次都创建一个数组实例。这就是区别

通过更改构造函数,您可以更清楚地看到它:

static EmptyArray()
{
   Instance = new T[0];
   Console.WriteLine("Array of "+ typeof(T) + " is created.");
}

var s = EmptyArray<string>.Instance;
s = EmptyArray<string>.Instance;
s = EmptyArray<string>.Instance;

var i = EmptyArray<int>.Instance;
i = EmptyArray<int>.Instance;

// output:
// Array of System.String is created.
// Array of System.Int32 is created.
static EmptyArray()
{
实例=新的T[0];
WriteLine(“创建了“+typeof(T)+”数组);
}
var s=EmptyArray.Instance;
s=EmptyArray.Instance;
s=EmptyArray.Instance;
var i=EmptyArray.Instance;
i=EmptyArray.Instance;
//输出:
//已创建System.String的数组。
//已创建System.Int32的数组。
这是:

var emptyStringArray = new string[0];
每次调用空字符串数组时,都会创建一个空字符串数组的新实例,并会产生所有相关的内存分配开销,而这:

public static class EmptyArray<T>
    {
        public static readonly T[] Instance;

        static EmptyArray()
        {
            Instance = new T[0];
        }
    }
公共静态类EmptyArray
{
公共静态只读T[]实例;
静态空数组()
{
实例=新的T[0];
}
}

仅创建空字符串数组的单个实例,而不管调用
实例
字段多少次。

jus为了说明这如何提高性能和内存,您可以尝试一下

using System;

namespace ConsoleApplication11
{
    class Program
    {
        static void Main(string[] args)
        {
            var str = EmptyArray<string>.Instance;
            var intTest = EmptyArray<int>.Instance;
            var intTest1 = EmptyArray<int>.Instance;  
            var str1 = EmptyArray<string>.Instance;
            Console.WriteLine(str.GetType());
            Console.WriteLine(intTest.GetType());
            if (ReferenceEquals(str,str1))
            {
                Console.WriteLine("References are equals");
            }
            if (ReferenceEquals(intTest,intTest1))             
            {
                Console.WriteLine("References are equals");
            }

        }
    }

    public static class EmptyArray<T>
    {
        public static readonly T[] Instance;

        static EmptyArray()
        {
            Instance =  new T[0];
        }
    }
}
使用系统;
命名空间控制台应用程序11
{
班级计划
{
静态void Main(字符串[]参数)
{
var str=EmptyArray.Instance;
var intTest=EmptyArray.Instance;
var intTest1=EmptyArray.Instance;
var str1=EmptyArray.Instance;
Console.WriteLine(str.GetType());
WriteLine(intTest.GetType());
if(ReferenceEquals(str,str1))
{
Console.WriteLine(“引用等于”);
}
if(ReferenceEquals(intTest,intTest1))
{
Console.WriteLine(“引用等于”);
}
}
}
公共静态类EmptyArray
{
公共静态只读T[]实例;
静态空数组()
{
实例=新的T[0];
}
}
}

您可以看到,即使对于值类型,也不需要其他分配,并且考虑到对象的分配和销毁会耗费时间和内存,您可以通过这样做来增强代码

,尽管在没有静态构造函数的情况下,这可能会更有效。。。只需使用
publicstaticreadonly T[]Instance=newt[0]。对时间的保证较少,但效率会稍高一些。(我可能会自己使用一个属性,但这不会影响任何事情。)它不仅创建空字符串数组,还创建其他类型的空数组。如果像这样创建不同的数组会是什么情况:var emptyStrArr=EmptyArray.Instance;var emptyFooArr=EmptyArray.Instance;var emptyBarArr=EmptyArray.Instance@JonSkeet:你能详细说明一下“更少的时间保证”吗?@akash88将为每种类型第一次创建一个实例。然后,如果使用相同的类型,则将获得先前创建的实例,而不是新实例one@Selman22:这不是意味着var emptyStrArr=EmptyArray.Instance;var emptyFooArr=EmptyArray.Instance;var emptyBarArr=EmptyArray.Instance;与var emptyStrArr=新字符串[0]相同;var emptyFooArr=新Foo[0];var emptyBarArr=新条[0];这不是意味着var-emptyStrArr=EmptyArray.Instance;var emptyFooArr=EmptyArray.Instance;var emptyBarArr=EmptyArray.Instance;与var emptyStrArr=新字符串[0]相同;var emptyFooArr=新Foo[0];var emptyBarArr=新条[0];请注意,自.NET 4.6以来,您可以使用Array.Empty()-请参阅
using System;

namespace ConsoleApplication11
{
    class Program
    {
        static void Main(string[] args)
        {
            var str = EmptyArray<string>.Instance;
            var intTest = EmptyArray<int>.Instance;
            var intTest1 = EmptyArray<int>.Instance;  
            var str1 = EmptyArray<string>.Instance;
            Console.WriteLine(str.GetType());
            Console.WriteLine(intTest.GetType());
            if (ReferenceEquals(str,str1))
            {
                Console.WriteLine("References are equals");
            }
            if (ReferenceEquals(intTest,intTest1))             
            {
                Console.WriteLine("References are equals");
            }

        }
    }

    public static class EmptyArray<T>
    {
        public static readonly T[] Instance;

        static EmptyArray()
        {
            Instance =  new T[0];
        }
    }
}