struct vvvv 
{
    public int j = 8;

    //public vvvv() { } error    
}

class cccc 
{
    public int f = 8;
}

在 struct 中,如果我注释掉构造函数,编译器告诉我,字段j在我指定显式构造函数之前不会被初始化,而在类的情况下,初始化器将在隐式构造函数的主体运行之前完美地运行.

我的意思是,该 struct 也有一个隐式构造函数.为什么我必须指定一个显式的初始值设定项才能运行?隐式构造函数还不够吗?

推荐答案

TL;DR

C#编译器不会为 struct 生成默认的ctor,因此如果有未声明的-字段初始化器将不会运行,因此它们基本上没有意义,为了防止这种意外行为,编译器不允许在没有声明ctor的情况下使用字段初始化器(不一定是默认的).

The longer rant:

首先,正如this answer(在编辑部分)所解释的那样:

无参数构造函数不是由编译器创建的.就CLR而言,值类型不一定要有构造函数--尽管事实证明,如果您用IL编写它,它就可以.当您用C#编写new Guid()时,它会发出与调用普通构造函数时不同的IL.

the following:

Console.WriteLine(typeof(Struct).GetConstructors().Length); // prints 0
Console.WriteLine(typeof(Class).GetConstructors().Length); // prints 1

struct Struct
{
}

class Class
{
}

(请注意,对于struct Struct{ public Struct() { } },上面的代码将打印1)

因此,其中一个原因可能是性能和向后兼容性.

此外,还有一些关于这LDM个主题的注释:

我们觉得这里的一条简单规则是用引用类型映射观察到的行为:如果 struct 类型没有显式构造函数,我们将合成该构造函数.如果构造函数碰巧为空(就像今天在无构造函数 struct 类型中一样,因为字段初始值设定项还不受支持),我们就不再优化该构造函数.如果显式声明了构造函数,我们将不会合成该类型的任何构造函数,并且除非也显式声明了无参数构造函数,否则new S()将不会运行字段初始值设定项.这确实有一个潜在的失败trap ,用户希望无参数构造函数运行字段初始值设定项,但合成一个无参数构造函数会对具有主构造函数的记录 struct 产生不良的连锁react :无参数构造函数会在那里做什么?它没有任何可以用来调用主构造函数的东西,并且会导致语义混乱.

这导致drat specification人中增加了以下几个:

如果 struct 具有字段初始值设定项而没有声明的实例构造函数,则会报告错误,因为字段初始值设定项将不会运行.

如果未声明无参数实例构造函数,则 struct (请参见§15.4.9)...

隐式具有一个无参数的实例构造函数,该构造函数始终返回将所有值类型字段设置为其缺省值并将所有引用类型字段设置为空的值.

结果是这quite noteworthy behaviour个:

Console.WriteLine(new V().j);  // prints 8
Console.WriteLine(new V1().j); // prints 0 - no custom parameterless ctor, no init

struct V
{
    public V() { }
    public V(int _) {}

    public int j = 8;
}

struct V1
{
    public V1(int _) { }

    public int j = 8;
}

P.S.

请注意,似乎至少有一些.NET 6 SDK版本不能正确地违反上面的规范,即:

Console.WriteLine(new V().j);

struct V
{
    public int j = 8;
}

不仅是compiles but prints 8:

enter image description here

尽管这个问题似乎已经在最新的(在 compose 本文时)6.0.400SDK中得到了修复.

Csharp相关问答推荐

ASP.NET核心结果.文件vs结果.流

ASP.NET MVC中创建视图的过滤器

如何使用while循环实现异常处理

使用LayoutKind在C#中嵌套 struct .显式

`Task`只有在C#中等待时才会运行吗?

如何定义EFCore中的多个穿透

如何在NodaTime中为Instant添加一年?

模型绑定RazorPage表单

无法通过绑定禁用条目

Savagger使用Fastendpoint更改用户界面参数

在.NET 8最低API中从表单绑定中排除属性

正在从最小API-InvocationConext.Arguments中检索参数的FromBodyAttribute

如何从Azure函数使用Graph API(SDK 5.35)中的[FindMeetingTimes]

多个选项卡上的MudForm验证

如何使用实体框架核心对字符串_agg使用强制转换为varchar(Max)

.NET EF Core Automapper项目到筛选不起作用

如何在C#中反序列化Java持续时间?

将两个JSON文件与覆盖值的主文件合并

是否在异步方法中避免Span<;T>;.ToArray()?

如何提高C#中比较大 struct 的性能?