在.Net 8中集合初始化的新语法

前言

在.Net 8中C#的版本也升级到了12.在集合初始化这一块也带来新的语法,在集合初始化的时候,更方便了.目前来看这是一个语法糖.

这个集合初始化的语法,主要在
  1. 数组
  2. Span<T>和ReadOnlySpan<T>
  3. List<T>

代码示例

// 数组
// //使用[]代替new in[],不用写具体示例化类型
int[] a = [1, 2, 3, 4, 5, 6, 7, 8]; 

// Span 
Span<int> b  = ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i'];

// 创建二维数组
int[][] twoD = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

为了确定这个新语法,是否为是语法糖,用IlSpy反编译生成后的代码,发现IlSpy目前还不支持C# 12的语法,用C# 11和IL反编译生成后的代码:

C# 12 集合初始化新语法

C# 12 集合初始化新语法,查看生成的IL代码

性能测试和汇编代码分析

using BenchmarkDotNet.Attributes;

namespace CSharpBenchmarks.ArrayTest
{
	[MemoryDiagnoser]
	[DisassemblyDiagnoser(printSource: true)]
	public class NewSyntaxTest
	{
		[Params(10000)]
		public int Times { get; set; }

		[Benchmark]
		public void ArrayTest1()
		{
			for (int i = 0; i < Times; i++)
			{
				int[] arr = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
				if (arr.Length > 0)
				{

				}
			}
		}

		[Benchmark]
		public void ArrayTest2()
		{
			for (int i = 0; i < Times; i++)
			{
				int[] arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
				if (arr.Length > 0)
				{

				}
			}
		}
	}
}

性能测试结果:

C# 12 集合初始化新语法,性能测试

发现性能测试在耗时上有微小的差异,在生成汇编代码和GC及内存分配上,都是一样的,在对比生成汇编代码后,可以确定这个语法就是语法糖,只是简化集合初始化而已.下面我们来看看汇编代码:

; CSharpBenchmarks.ArrayTest.NewSyntaxTest.ArrayTest2()
; 			for (int i = 0; i < Times; i++)
; 			     ^^^^^^^^^
; 				int[] arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
; 				^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; 				if (arr.Length > 0)
; 				^^^^^^^^^^^^^^^^^^^
       push      rdi
       push      rsi
       push      rbx
       sub       rsp,20
       vzeroupper
       mov       rbx,rcx
       xor       esi,esi
       cmp       dword ptr [rbx+8],0
       jle       short M00_L01
       mov       rdi,offset MT_System.Int32[]
M00_L00:
       mov       rcx,rdi
       mov       edx,0A
       call      CORINFO_HELP_NEWARR_1_VC     ;;创建数组
       mov       rcx,1E73D3286D0
       vmovdqu   ymm0,ymmword ptr [rcx]
       vmovdqu   ymmword ptr [rax+10],ymm0
       mov       rdx,[rcx+20]
       mov       [rax+30],rdx
       inc       esi
       cmp       esi,[rbx+8]
       jl        short M00_L00
M00_L01:
       add       rsp,20
       pop       rbx
       pop       rsi
       pop       rdi
       ret
; Total bytes of code 86

只看新语法生成的汇编代码,其实和new int[]是一样的.

在.Net 8中BCL库和Asp.Net Core中已经开始使用新语法,可以看一下这个Issue #93126

dotnet 8 BCL已经开始使用新语法替换老语法

秋风 2023-10-09