Say I have a struct
public struct Foo
{
...
}
Is there any difference between
Foo foo = new Foo();
and <
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.
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 nop
s, ret
s 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?).
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
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
}
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.