The default keyword is a powerful tool in C#. For reference types, it returns null, and for value types (structs), it returns a zeroed-out value. Interestingly, default(T) and new T() can yield different results for structs (check out Get the default value of a type at runtime for more info). Initially, C# required default(T), but now you can simply use default when the type can be inferred by the compiler.
But how does the compiler infer the type? And can you always trust it to get it right? Let's dive in and find out!
Let's consider two simple cases:
C#
// Infer from the left hand side
int foo = default;
// Infer from the parameter type
Foo(default);
void Foo(int bar) => throw null;
The previous cases are straightforward. The compiler can infer the type from the left-hand side or the parameter type. But what happens with a switch expression?
C#
var sample = new byte[0];
ReadOnlyMemory<byte> foo = sample switch
{
byte[] value => value,
_ => default,
};
You may expect default to be default(ReadOnlyMemory<byte>) since that is the visible type on the left-hand side. However, it is actually default(byte[]). The compiler infers the type from the switch expression arms by determining the best common type across all cases, which here is byte[]. Therefore, the type of default is byte[].
In the previous example, the result is the same whether you use default(byte[]) or default(ReadOnlyMemory<byte>). But this can have implications. Let's switch the type from ReadOnlyMemory<byte> to ReadOnlyMemory<byte>? (nullable).
C#
var sample = new object();
ReadOnlyMemory<byte>? foo = sample switch
{
byte[] value => value,
_ => default, // default(byte[])
};
In the previous example, the type of default is still byte[]. So the switch expression returns default(byte[]), which is null. However, this null value is then converted to ReadOnlyMemory<byte>?, resulting in an empty ReadOnlyMemory<byte> rather than a null nullable. Therefore, foo.HasValue will be true!
In your IDE, you can see the inferred type of default by hovering over it. For example, in Visual Studio, the tooltip shows:
Visual Studio showing the actual type of default
If you think VS should be more explicit, you can vote for this issue.
Do you have a question or a suggestion about this post? Contact me!