Get the default value of a type at runtime
Getting the default value of a type at compile time is easy. You can use default(T)
. What if you want to do the same at runtime? What is the default value for any System.Type
?
You can find multiple wrong answers on the internet. For example, this one:
// ⚠️ Not the same as default(T)
object? GetDefaultValue(Type type)
=> type.IsValueType ? Activator.CreateInstance(type) : null;
This works great for reference types and most value types. But Activator.CreateInstance(T)
is not the same as default(T)
when T
is a value type. Activator.CreateInstance(T)
is the same as new T()
. So, it calls the default constructor. default(T)
doesn't call the default constructor. It initializes all fields to their default value.
In C# 10, you can create struct
with a default constructor:
struct Sample
{
public int Value { get; }
public Sample() => Value = 1;
}
Let's see the difference between default(Sample)
and new Sample()
:
default(Sample).Value // 0
new Sample().Value // 1
Activator.CreateInstance<Sample>().Value // 1
So, how to get the default(T)
value at runtime?
One solution is to use to System.Linq.Expression
, but this is a little bit slow (~20ms):
object? GetDefaultValue(Type type)
{
if (type.IsValueType)
{
var defaultExpression = Expression.Default(type);
return Expression.Lambda(defaultExpression).Compile().DynamicInvoke();
}
return null;
}
Another solution is to construct a generic class with a static property that returns the default value of the generic type. This is faster (~1.5ms):
object? GetDefaultValue(Type type)
{
if (type.IsValueType)
{
var defaultType = typeof(DefaultProvider<>).MakeGenericType(type);
return defaultType.InvokeMember("Value", BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty, binder: null, target: null, args: null, culture: null);
}
return null;
}
private static class DefaultProvider<T>
{
public static T? Value => default;
}
Starting with .NET Core 2.0, you can use System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject
(documentation) to get a new uninitialized instance:
object? GetDefaultValue(Type type)
{
if (type.IsValueType)
return RuntimeHelpers.GetUninitializedObject(type);
return null;
}
You can use the previous method to get the default value of a generic type:
((Sample)GetDefaultValue(typeof(Sample))).Value // 0
Do you have a question or a suggestion about this post? Contact me!