为何结构体带字段初始化器需显式构造函数而类无需?
结构体与类的字段初始化器差异解析
示例代码
struct vvvv { public int j = 8; //public vvvv() { } error } class cccc { public int f = 8; }
问题
在结构体vvvv中,若注释掉显式构造函数,编译器会提示字段j需指定显式构造函数才会完成初始化;而在类cccc中,字段初始化器可在隐式构造函数体执行前正常运行。结构体同样存在隐式构造函数,为何必须指定显式构造函数才能让初始化器生效?隐式构造函数为何无法满足需求?
解答
核心原因是结构体是值类型,类是引用类型,二者的隐式构造函数本质完全不同:
- 对于类这种引用类型,隐式无参构造函数是编译器生成的,它会自动把字段初始化器的代码插入到构造函数体的最开头,所以
f=8这类自定义初始化逻辑能正常执行。 - 但结构体的隐式无参构造函数是CLR底层实现的,它的唯一作用就是把结构体所有字段置为默认值(比如int类型设为0,bool类型设为false),这个行为是固定死的,编译器根本无法将你写的字段初始化器(比如
j=8)的逻辑注入进去。
当你给结构体字段添加了自定义初始化器,编译器需要确保这个逻辑一定会被执行,但隐式构造函数完全做不到——它只会无视你的初始化器,强制把字段设为默认值。因此编译器会要求你必须编写显式构造函数,以此保证自定义初始化逻辑能被执行(在C# 7.3及以后版本中,你也可以编写显式的无参构造函数来包含初始化逻辑)。
另外补充:早期C#版本不允许结构体定义自己的无参构造函数,C# 7.3才放开了这个限制,但即使如此,结构体的隐式无参构造函数依然是CLR的默认行为,和你手动编写的显式无参构造函数是相互独立的两个逻辑。
内容的提问来源于stack exchange,提问作者Erik_JI
相关产品推荐
相关产品推荐

