C#struct new StructType()vs default(StructType)

Bal*_*a R 54 c# struct

说我有一个结构

public struct Foo
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

两者之间有什么区别吗?

Foo foo = new Foo();
Run Code Online (Sandbox Code Playgroud)

Foo foo = default(Foo);
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 71

您可能想知道为什么,如果它们完全相同,有两种方法可以做同样的事情.

它们并不完全相同,因为每个引用类型或值类型都保证具有默认值,但并不是每个引用类型都保证具有无参数构造函数:

static T MakeDefault<T>()
{
    return default(T); // legal
    // return new T(); // illegal
}
Run Code Online (Sandbox Code Playgroud)

  • @Jason:关于规范 - 使用反射,你实际上可以区分具有默认ctor的结构和不具有默认ctor的结构.所以在那个级别,结构甚至可能没有*ctor.也许规范可能会告诉我们一个"软谎言"?(我所说的可能完全是胡说八道;希望埃里克可以澄清). (2认同)
  • @BenMosher:在这种情况下,`new T()`和`default(T)`是相同的,编译器将为两者生成相同的代码. (2认同)
  • @EricLippert 随着 C# 10.0 中引入的“结构字段初始值设定项”,“new T()”将返回一个结构体,其中字段根据其初始值设定项进行初始化,而“default(T)”会将字段设置为零(https:// dotnetfiddle.net/NnWDfT)。 (2认同)

And*_*are 17

不,两个表达式都会产生相同的结果.

由于结构不能包含显式无参数构造函数(即您不能自己定义),默认构造函数将为您提供结构的版本,其中所有值都为零.这也是同样的行为default.

  • +1我刚刚尝试过,这两个表达式生成了相同的IL. (5认同)
  • 如果存在无差异的ctor,它们会产生不同的IL; 看到我的回答. (3认同)

Ani*_*Ani 14

对于价值类型,实际上,这些选项是 等价的.

然而,我对Jon Skeet的实证研究很感兴趣,当在CIL中指定时,'指令'会导致调用struct的无参数默认构造函数(你不能在C#中这样做,因为它不会让你).除此之外,他还试过了default(T),类型参数new T()在哪里T.它们似乎相同; 他们似乎都没有打电话给构造函数.

但一个情况下(似乎)他没有试图为 default(Foo)那里Foo是一个实际的结构类型.

所以我把他的代码用于'黑客'结构并为我自己尝试了.


事实证明,默认(Foo)不会调用构造函数,而新的Foo()实际上就是这样.

使用Oddity指定无参数构造函数的结构类型:

关闭优化后,方法:

private void CallDefault()
{
    Oddity a = default(Oddity);
}
Run Code Online (Sandbox Code Playgroud)

产生CIL(没有nops,rets等):

L_0001: ldloca.s a
L_0003: initobj [Oddity]Oddity
Run Code Online (Sandbox Code Playgroud)

而方法:

private void CallNew()
{
    Oddity b = new Oddity();
}
Run Code Online (Sandbox Code Playgroud)

生产:

L_0001: ldloca.s b
L_0003: call instance void [Oddity]Oddity::.ctor()
Run Code Online (Sandbox Code Playgroud)

随着优化开启,编译器似乎非常优化掉所有的的CallDefault方法为无操作,但保持在调用构造函数CallNew(潜在的副作用?).


jas*_*son 12

语言规范(§4.1.2和§5.2)是你的朋友.特别:

对于value-type的变量,默认值与value-type的默认构造函数(第4.1.2节)计算的相同.

(斜体字原文.)

请注意,这与引用类型不同.

对于reference-type的变量,默认值为null.

这与默认构造函数(如果存在)生成的值明显不同.


Sno*_*ear 5

default 当您不知道确切的类型时,关键字非常有用,它不仅适用于结构,例如泛型:

T FirstOrDefault(IEnumerable<T> source)
{
    if (...source is empty...) return default(T);
}
Run Code Online (Sandbox Code Playgroud)

这将为引用类型返回null,为基本类型返回默认值(0表示数字,false表示bool),默认为inialized结构等...

当类型是在编译时知道这是没有意义的使用default,就可以使用new Foo(),而不是