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

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

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?Buy Me A Coffee💖 Sponsor on GitHub