180

For any given type i want to know its default value.

In C#, there is a keyword called default for doing this like

object obj = default(Decimal);

but I have an instance of Type (called myType) and if I say this,

object obj = default(myType);

it doesn't work

Is there any good way of doing this? I know that a huge switch block will work but thats not a good choice.

Chuck Conway
  • 16,287
  • 11
  • 58
  • 101
viky
  • 17,275
  • 13
  • 71
  • 90
  • Can you explain why it doesn't work? Do get an error? Does it just not return what you expect? – Gabe Mar 22 '10 at 06:34
  • 1
    @gabe, It works with type name but not with Type instance of that type name, I mean default(Decimal) works but default(typeof(Decimal)) doesn't – viky Mar 22 '10 at 07:19

6 Answers6

309

There's really only two possibilities: null for reference types and new myType() for value types (which corresponds to 0 for int, float, etc) So you really only need to account for two cases:

object GetDefaultValue(Type t)
{
    if (t.IsValueType)
        return Activator.CreateInstance(t);

    return null;
}

(Because value types always have a default constructor, that call to Activator.CreateInstance will never fail).

Andrew Bullock
  • 36,616
  • 34
  • 155
  • 231
Dean Harding
  • 71,468
  • 13
  • 145
  • 180
  • 24
    I posted the same solution but I was unsure about how nullables were treated. It turns out nullables fall into the first branch but Activator.CreateInstance(typeof(int?)) actually returns null so it all works out. – Josh Mar 22 '10 at 06:08
  • @Josh: Interesting... I did a quick test of my solution and `int?` came out with the expected `null`, but I didn't actually test whether `typeof(int?).IsValueType` returned true or false. – Dean Harding Mar 22 '10 at 06:10
  • Yeah. This gets you into the hairy business of re-implementing the C# compiler's default() operator at run-time. It's pretty simple to do but, if the rules for defaulting were to be extended to take into account a new scenario, you have to update your code. –  Mar 22 '10 at 06:11
  • I'm pretty sure that the poster wants `Activator.CreateInstance(t)` in all cases. The reason he asked the question is because he *doesn't* want `null` for non-value types. – Gabe Mar 22 '10 at 06:13
  • 1
    @gabe, no the OP said he wanted to use default(myType) except that it requires a constant type or generic type argument when all he has is a Type instance at runtime. I read his question the same as codeka. – Josh Mar 22 '10 at 06:19
  • 1
    someone look into the performance implications of Activator.CreateInstance vs the generic default() ? – Guillaume86 Feb 13 '12 at 16:22
  • 12
    For information (and because I ran into the problem), System.Void is considered a ValueType, but cause an exception on CreateInstance. If you use this code to get the default return value of a method, you'll need to consider System.Void ! – Vivien Ruiz Mar 20 '12 at 08:51
  • @DeanHarding I need to get the type's default value but I'm not using reflection (I'm using [FastMember](https://code.google.com/p/fast-member) because of the performance issues. I don't know how slow is this `Activator.CreateInstance` method, do you think this could be a problem? – Ashkan Oct 07 '13 at 17:46
  • 1
    This will fail for `string`, whereas the `default` operator won't. – Shimmy Weitzhandler Apr 19 '15 at 03:14
  • 3
    @Shimmy Why would this fail for string? The default value of string is null. – Mike Zboray Apr 19 '15 at 03:17
  • @mikez oops my bad. I didn't even notice the value type check. Sorry for that. – Shimmy Weitzhandler Apr 19 '15 at 03:26
  • `Nullable` is a value type, therefore an instance of it cannot be a null reference. Using `Activator.CreateInstance()` will return a new instance of it where its `HasValue` property is set to `false` and its private `value` field (which has a type of `T`) is set to `default(T)`. It is only a syntactic sugar (hack) that `instance == null` is evaluated to `true`. The equivalent check is `!instance.HasValue`. Note: if `HasValue` property is `false` then accessing `Value` property will throw an `InvalidOperationException`; otherwise, returns the value of the `value` field. – Gabor Jun 25 '16 at 18:42
  • 4
    @Gabor Actually in this case what's going on is that `Activator.CreateInstance` always returns a `System.Object`, so if you ask it to make an instance of a `ValueType`, it has to box it. `Nullable` has special-casing in the runtime for boxing so that the `Nullable` wrapper goes away and only the `T` is returned. When `HasValue` is false, though, the `object` reference is simply `null`. So, it really *is* legitimately an actual `null` reference coming out of e.g. `Activator.CreateInstance(typeof(int?))`, not an `int?`. There's probably an `int?` internally but it disappears during boxing. – Jonathan Gilbert Jul 14 '16 at 17:52
  • @JonathanGilbert, I did not want to believe it but tested some cases and I was very surprised by the result. `((int?)null).HasValue` returns `false` but `((int?)null).GetType()` throws a `NullReferenceException`. But it is also strange that `(new int?(5)).GetType().FullName` returns `System.Int32` and `Nullable.GetUnderlyingType(new int?(5))` returns `null`. I would expect `System.Nullable'1` type with the underlying type of `System.Int32`. So I think I need to read more about how nullable types are really handled. Thank you for your comment. – Gabor Jul 17 '16 at 20:38
  • Derp, how have I never noticed IsValueType? Exactly what I was looking for. – Billy Jake O'Connor May 27 '19 at 12:28
  • is interesting, that even if you get the default value of the value type, you cannot use it for comparison because object is reference type. I didn't find any solution how to compare value of value type boxed in an object with default value of that underlying value type – Muflix Aug 16 '21 at 21:40
41

You could also add it as an extension method to System.Type:

public static class TypeExtensions
{
    public static object GetDefaultValue(this Type t)
    {
        if (t.IsValueType && Nullable.GetUnderlyingType(t) == null)
            return Activator.CreateInstance(t);
        else
            return null;
    }
}
DavidWainwright
  • 2,895
  • 1
  • 27
  • 30
  • 21
    That 'else' drives me crazy :) – Mauro Sampietro Jan 02 '17 at 14:27
  • return (t.IsValueType && Nullable.GetUnderlyingType(t) == null) ? Activator.CreateInstance(t) : null; if you don't like it hangin there! – DavidWainwright Jul 11 '17 at 15:42
  • 1
    That's not about having just one 'return' it would make the code messy in this case. Really just remove the word 'else' since in the if you return.. if(....)return Activator.CreateInstance(t); return null; – Mauro Sampietro Jul 12 '17 at 07:29
  • 6
    I would use the ternary operator if I wanted to be succinct - it doesn't look messy. Including the else means the code is easier to grasp quickly. Removing it and just using "return null;" introduces implicitness. – DavidWainwright Jul 12 '17 at 07:49
  • 1
    what `Nullable.GetUnderlyingType(t) == null` is for? In which case it can be not null? – Muflix Aug 17 '21 at 06:24
  • @Muflix For Nullable, the underlying type would be int. If the type is nullable (ie. underlying type is not null) we know the default value is null so no need to create an instance of it. – mtone Jun 27 '22 at 05:03
20

Having solved this problem in my own systems, here is a method for correctly determining the default value of an arbitrary Type at run time, which has been tested against thousands of Types:

    /// <summary>
    /// [ <c>public static object GetDefault(this Type type)</c> ]
    /// <para></para>
    /// Retrieves the default value for a given Type
    /// </summary>
    /// <param name="type">The Type for which to get the default value</param>
    /// <returns>The default value for <paramref name="type"/></returns>
    /// <remarks>
    /// If a null Type, a reference Type, or a System.Void Type is supplied, this method always returns null.  If a value type 
    /// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an 
    /// exception.
    /// </remarks>
    /// <example>
    /// To use this method in its native, non-extension form, make a call like:
    /// <code>
    ///     object Default = DefaultValue.GetDefault(someType);
    /// </code>
    /// To use this method in its Type-extension form, make a call like:
    /// <code>
    ///     object Default = someType.GetDefault();
    /// </code>
    /// </example>
    /// <seealso cref="GetDefault&lt;T&gt;"/>
    public static object GetDefault(this Type type)
    {
        // If no Type was supplied, if the Type was a reference type, or if the Type was a System.Void, return null
        if (type == null || !type.IsValueType || type == typeof(void))
            return null;

        // If the supplied Type has generic parameters, its default value cannot be determined
        if (type.ContainsGenericParameters)
            throw new ArgumentException(
                "{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type +
                "> contains generic parameters, so the default value cannot be retrieved");

        // If the Type is a primitive type, or if it is another publicly-visible value type (i.e. struct/enum), return a 
        //  default instance of the value type
        if (type.IsPrimitive || !type.IsNotPublic)
        {
            try
            {
                return Activator.CreateInstance(type);
            }
            catch (Exception e)
            {
                throw new ArgumentException(
                    "{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe Activator.CreateInstance method could not " +
                    "create a default instance of the supplied value type <" + type +
                    "> (Inner Exception message: \"" + e.Message + "\")", e);
            }
        }

        // Fail with exception
        throw new ArgumentException("{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type + 
            "> is not a publicly-visible type, so the default value cannot be retrieved");
    }

In these examples, the GetDefault method is implemented in the static class DefaultValue. Call this method with a statement like:

        object Default = DefaultValue.GetDefault(someType);

To use the GetDefault method as an extension method for Type, call it like this:

        object Default = someType.GetDefault();

This second, Type-extension approach is a simpler client-code syntax, since it removes the need to reference the containing DefaultValue class qualifier on the call.

The above run time form of GetDefault works with identical semantics as the primitive C# 'default' keyword, and produces the same results.

To use a generic form of GetDefault, you may access the following function:

    /// <summary>
    /// [ <c>public static T GetDefault&lt; T &gt;()</c> ]
    /// <para></para>
    /// Retrieves the default value for a given Type
    /// </summary>
    /// <typeparam name="T">The Type for which to get the default value</typeparam>
    /// <returns>The default value for Type T</returns>
    /// <remarks>
    /// If a reference Type or a System.Void Type is supplied, this method always returns null.  If a value type 
    /// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an 
    /// exception.
    /// </remarks>
    /// <seealso cref="GetDefault(Type)"/>
    public static T GetDefault<T>()
    {
        return (T) GetDefault(typeof(T));
    }

A call to the generic form could be something like:

        int? inDefaultVal = DefaultValue.GetDefault<int?>();

Of course, the above generic form of GetDefault is unnecessary for C#, since it works the same as default(T). It is only useful for a .NET language that does not support the 'default' keyword but which supports generic types. In most cases, the generic form is unnecessary.

A useful corollary method is one to determine whether an object contains the default value for its Type. I also rely on the following IsObjectSetToDefault method for that purpose:

    /// <summary>
    /// [ <c>public static bool IsObjectSetToDefault(this Type ObjectType, object ObjectValue)</c> ]
    /// <para></para>
    /// Reports whether a value of type T (or a null reference of type T) contains the default value for that Type
    /// </summary>
    /// <remarks>
    /// Reports whether the object is empty or unitialized for a reference type or nullable value type (i.e. is null) or 
    /// whether the object contains a default value for a non-nullable value type (i.e. int = 0, bool = false, etc.)
    /// <para></para>
    /// NOTE: For non-nullable value types, this method introduces a boxing/unboxing performance penalty.
    /// </remarks>
    /// <param name="ObjectType">Type of the object to test</param>
    /// <param name="ObjectValue">The object value to test, or null for a reference Type or nullable value Type</param>
    /// <returns>
    /// true = The object contains the default value for its Type.
    /// <para></para>
    /// false = The object has been changed from its default value.
    /// </returns>
    public static bool IsObjectSetToDefault(this Type ObjectType, object ObjectValue)
    {
        // If no ObjectType was supplied, attempt to determine from ObjectValue
        if (ObjectType == null)
        {
            // If no ObjectValue was supplied, abort
            if (ObjectValue == null)
            {
                MethodBase currmethod = MethodInfo.GetCurrentMethod();
                string ExceptionMsgPrefix = currmethod.DeclaringType + " {" + currmethod + "} Error:\n\n";
                throw new ArgumentNullException(ExceptionMsgPrefix + "Cannot determine the ObjectType from a null Value");
            }

            // Determine ObjectType from ObjectValue
            ObjectType = ObjectValue.GetType();
        }

        // Get the default value of type ObjectType
        object Default = ObjectType.GetDefault();

        // If a non-null ObjectValue was supplied, compare Value with its default value and return the result
        if (ObjectValue != null)
            return ObjectValue.Equals(Default);

        // Since a null ObjectValue was supplied, report whether its default value is null
        return Default == null;
    }

The above IsObjectSetToDefault method can either be called in its native form or accessed as a Type-class extension.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Mark Jones
  • 2,024
  • 1
  • 19
  • 12
11

How about something like...

class Program
{
  static void Main(string[] args)
  {
    PrintDefault(typeof(object));
    PrintDefault(typeof(string));
    PrintDefault(typeof(int));
    PrintDefault(typeof(int?));
  }

  private static void PrintDefault(Type type)
  {
    Console.WriteLine("default({0}) = {1}", type,
      DefaultGenerator.GetDefaultValue(type));
  }
}

public class DefaultGenerator
{
  public static object GetDefaultValue(Type parameter)
  {
    var defaultGeneratorType =
      typeof(DefaultGenerator<>).MakeGenericType(parameter);

    return defaultGeneratorType.InvokeMember(
      "GetDefault", 
      BindingFlags.Static |
      BindingFlags.Public |
      BindingFlags.InvokeMethod,
      null, null, new object[0]);
  }
}

public class DefaultGenerator<T>
{
  public static T GetDefault()
  {
    return default(T);
  }
}

It produces the following output:

default(System.Object) =
default(System.String) =
default(System.Int32) = 0
default(System.Nullable`1[System.Int32]) =
  • Pretty complicated. See codeka's solution for a much more concise method. – Josh Mar 22 '10 at 06:10
  • I guess that depends on your definition of complicated. If twenty-four lines of code with a grand-total of two classes and three instructions is "complicated," then I guess you are right... Codeka's example also has three instructions so I can only assume that it is the "extra" class, then? –  Mar 22 '10 at 07:18
  • In addition to its unnecessary complication, this answer introduces a significant performance hit, namely in its use of MakeGenericType and calling the external generic method. Please consider my solution at http://stackoverflow.com/questions/2490244/default-value-of-a-type/7881481#7881481 to address these concerns. – Mark Jones Oct 24 '11 at 21:10
2

What do you mean by "Default Value"? All reference Types ("class") have null as default value, while all value types will have their default values according to this table.

Michael Stum
  • 177,530
  • 117
  • 400
  • 535
  • 5
    There is a notable exception to the rules you mentioned. That is, a nullable ValueType always has a default value of null, not a default value of its underlying ValueType. A nullable ValueType is nonetheless still a ValueType. Also remember that although a generic class definition (type.ContainsGenericParameters == true) is technically considered a reference Type, it has no default value, since it cannot be directly instantiated. Please refer to my solution at http://stackoverflow.com/questions/2490244/default-value-of-a-type/7881481#7881481 for further detail and examples. – Mark Jones Oct 24 '11 at 21:01
  • 1
    ...More like the Nullable type is a generic ValueType and its default value is an instance of Nullable with its Value property set to the default value of type T and its HasValue property set to false. My point is that a nullable type _is_ never null, that is just compiler magic to make nullables more easy to use when you are writing code. What you write: `object a = myNullable;` what the compiler sees: `object a = myNullable.HasValue ? myNullable.Value : null;`. So technically default of Nullables _does_ have a default value of its "underlying" (generic) type - but it's not exposed. – AnorZaken Jan 08 '16 at 14:43
2

Here's a function that will return the default value for a nullable type (in other words, it returns 0 for both Decimal and Decimal?):

public static object DefaultValue(Type maybeNullable)
{
    Type underlying = Nullable.GetUnderlyingType(maybeNullable);
    if (underlying != null)
        return Activator.CreateInstance(underlying);
    return Activator.CreateInstance(maybeNullable);
}
Gabe
  • 84,912
  • 12
  • 139
  • 238
  • 3
    You do not want to return the ValueType default for a nullable Type, since this is not the correct default. The correct default for a nullable Type is null. So regarding your example, Decimal should have a default of 0, but Decimal? should have a default of null. See my solution in detail at http://stackoverflow.com/questions/2490244/default-value-of-a-type/7881481#7881481, which works correctly for all nullable Types as well. – Mark Jones Oct 24 '11 at 20:45