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

2020-05-14 13:32发布

问题:

Say I have a struct

public struct Foo
{
    ...
}

Is there any difference between

Foo foo = new Foo();

and

Foo foo = default(Foo);

?

回答1:

You might wonder why, if they are exactly the same, there are two ways to do the same thing.

They are not quite the same because every reference type or value type is guaranteed to have a default value but not every reference type is guaranteed to have a parameterless constructor:

static T MakeDefault<T>()
{
    return default(T); // legal
    // return new T(); // illegal
}


回答2:

No, both expressions will yield the same exact result.

Since structs cannot contain explicit parameterless constructors (i.e. you cannot define one yourself) the default constructor will give you a version of the struct with all values zero'd out. This is the same behavior that default gives you as well.



回答3:

The language specification (§4.1.2 and §5.2) is your friend. Specifically:

For a variable of a value-type, the default value is the same as the value computed by the value-type’s default constructor (§4.1.2).

(Italics in original.)

Note that this is not the same for reference types.

For a variable of a reference-type, the default value is null.

This is emphatically different than the value produced by a default constructor, if one exists.



回答4:

For value-types, the options are, practically speaking, equivalent.

However, I was intrigued by Jon Skeet's empirical research into which 'instructions' result in the invocation of a struct's parameterless default constructor when it is specified in CIL (you can't do it in C# because it doesn't let you). Amongst other things, he'd tried out default(T) and new T() where T is a type parameter. They appeared equivalent; neither of them appeared to call the constructor.

But the one case (it appears) he hadn't tried was default(Foo) where Foo is an actual struct type.

So I took his code for the 'hacked' struct and tried that out for myself.


It turns out that default(Foo) doesn't call the constructor, whereas new Foo() in fact does.

Using a struct type Oddity that specifies a parameterless constructor:

With optimizations turned off, the method:

private void CallDefault()
{
    Oddity a = default(Oddity);
}

produces the CIL (without nops, rets etc.):

L_0001: ldloca.s a
L_0003: initobj [Oddity]Oddity

whereas the method:

private void CallNew()
{
    Oddity b = new Oddity();
}

produces:

L_0001: ldloca.s b
L_0003: call instance void [Oddity]Oddity::.ctor()

With optimizations turned on, the compiler appears to optimize away pretty much all of the CallDefault method into a no-op, but keeps the call to the constructor in CallNew (for potential side-effects?).



回答5:

default keyword is useful when you do not know exact type and it works not only for structs, for example in generics:

T FirstOrDefault(IEnumerable<T> source)
{
    if (...source is empty...) return default(T);
}

This will return null for reference types, default value for primitive types(0 for numbers, false for bool), defaultly inialized structure, etc ...

When type is known at compile-time it makes no sense to use default, you can use new Foo() instead



标签: c# struct