使用自定义record复制构造函数时字段未初始化的原因?
问题:C# Record自定义复制构造函数后字段初始化失效
定义如下Record类型:
record Foo { string _bar = "initialized"; public string Bar => _bar; }
运行测试代码:
var foo = new Foo(); Console.WriteLine(foo?.Bar ?? "null"); var foo2 = foo with { }; Console.WriteLine(foo2?.Bar ?? "null");
输出结果:
initialized initialized
但添加自定义复制构造函数后:
protected Foo(Foo other) { Console.WriteLine("---my cloning method---"); }
重新运行测试代码,输出变为:
initialized ---my cloning method--- null
疑问:自定义复制构造函数未执行字段初始化代码,按常理编译器会将字段初始化代码注入构造函数,为何此处未生效?
解答
这是C# Record的设计规则导致的:
- 未自定义复制构造函数时,编译器会自动生成默认复制构造函数,这个自动生成的构造函数会同时处理两件事:执行字段的初始化代码(比如
_bar = "initialized"),以及从原实例复制所有字段的值。 - 一旦手动定义了复制构造函数,编译器就会停止生成默认的复制逻辑,完全交由开发者实现构造函数内容。此时字段初始化代码不会自动注入到自定义复制构造函数中,也不会自动复制原实例的字段值。
你的自定义复制构造函数里没有对_bar做任何赋值操作,所以它会保持字符串类型的默认值null,最终输出null。
如果需要保留原实例的字段状态,只需在自定义复制构造函数中手动复制原实例的字段:
protected Foo(Foo other) { Console.WriteLine("---my cloning method---"); _bar = other._bar; // 手动复制原实例的_bar字段值 }
这样修改后,运行测试代码就会重新输出两次initialized,同时触发自定义构造函数的日志。
内容的提问来源于stack exchange,提问作者Ivan Petrov
相关产品推荐
相关产品推荐

