如何避免C# readonly record struct中的防御性副本?
关于readonly record struct防御性副本的疑问与验证
初始定义与原理解读
首先定义一个readonly record struct:
public readonly record struct S(int A, int B) { }
此前误以为record的位置参数会自动实现为属性,访问A和B会产生防御性副本,因此尝试手动定义readonly字段来规避:
public readonly record struct S(int A, int B) { public readonly int A = A; public readonly int B = B; }
此时A和B是字段,访问无副作用,且测试发现两种定义下编译器生成的record专属代码(相等性、哈希码生成等)一致。
补充测试与结论
后续补充了多层嵌套的测试代码:
const int SIZE = 10000; var sw = new Stopwatch(); A[] aArray = new A[SIZE]; M[] mArray = new M[SIZE]; for(int repeat = 0; repeat < SIZE; repeat++) aArray[repeat] = new A(new(new(new(new(new(new(new(new(new(new(new(Random.Shared.Next())))))))))))); for(int repeat = 0; repeat < SIZE; repeat++) mArray[repeat] = new M(new(Random.Shared.Next())); int i = 0; sw.Start(); for(int repeat = 0; repeat < SIZE; repeat++) i =+ aArray[repeat].B.C.D.E.F.G.H.I.J.K.L.I; sw.Stop(); System.Console.WriteLine(i); System.Console.WriteLine(sw.Elapsed); sw.Reset(); sw.Start(); for(int repeat = 0; repeat < SIZE; repeat++) i =+ mArray[repeat].N.I; sw.Stop(); System.Console.WriteLine(i); System.Console.WriteLine(sw.Elapsed); // 手动定义readonly字段的版本 readonly record struct A(B B){public readonly B B = B;} readonly record struct B(C C){public readonly C C = C;} readonly record struct C(D D){public readonly D D = D;} readonly record struct D(E E){public readonly E E = E;} readonly record struct E(F F){public readonly F F = F;} readonly record struct F(G G){public readonly G G = G;} readonly record struct G(H H){public readonly H H = H;} readonly record struct H(I I){public readonly I I = I;} readonly record struct I(J J){public readonly J J = J;} readonly record struct J(K K){public readonly K K = K;} readonly record struct K(L L){public readonly L L = L;} readonly record struct L(int I){public readonly int I = I;} readonly record struct M(N N){public readonly N N = N;} readonly record struct N(int I){public readonly int I = I;} // 自动生成属性的版本 readonly record struct A(B B){} readonly record struct B(C C){} readonly record struct C(D D){} readonly record struct D(E E){} readonly record struct E(F F){} readonly record struct F(G G){} readonly record struct G(H H){} readonly record struct H(I I){} readonly record struct I(J J){} readonly record struct J(K K){} readonly record struct K(L L){} readonly record struct L(int I){} readonly record struct M(N N){} readonly record struct N(int I){}
重新测试后发现两种定义的耗时相近,此前的理解有误,两种情况均不会产生防御性副本。
核心疑问
- 是否存在更优方式避免record的防御性副本?
- 手动定义所有readonly字段繁琐且易出错,有没有对应的C#语法可以简化这个操作?
- 若对防御性副本及record代码生成的理解仍有错误,请予以纠正。
内容的提问来源于stack exchange,提问作者patvax
相关产品推荐
相关产品推荐

