Get the default value of a type at runtime

 
 
  • Gérald Barré

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:

C#
// ⚠️ Not the same as default(T)
object? GetDefaultValue(Type type)
    => type.IsValueType ? Activator.CreateInstance(type) : null;

This works well for reference types and most value types. However, Activator.CreateInstance(T) is not the same as default(T) when T is a value type. Activator.CreateInstance(T) is equivalent to new T(), which calls the default constructor. default(T) does not call the default constructor; it initializes all fields to their default values.

In C# 10, you can create struct with a default constructor:

C#
struct Sample
{
    public int Value { get; }

    public Sample() => Value = 1;
}

Let's see the difference between default(Sample) and new Sample():

C#
default(Sample).Value // 0

new Sample().Value // 1
Activator.CreateInstance<Sample>().Value // 1

So, how do you get the default(T) value at runtime?

One solution is to use System.Linq.Expression, but this is slow (~20ms):

C#
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):

C#
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:

C#
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:

C#
((Sample)GetDefaultValue(typeof(Sample))).Value // 0

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?