Non-generic default values in C#? Why not?!

A relatively obscure new keyword in C# 2.0 is the default(T) keyword.
It's shorthand for checking if the given generic parameter T is a value type or reference type. If it's a reference type, it returns null. Otherwise it returns 0/false/0.0 or whatever the default value for the type is.

For some reason, though, it can only be used on generic parameters. Why can't I use default(typeof(int)) to get 0? Or, more realistically, default(myUnknownType) to return the default value?

A workaround is to check if it's a value type with reflection, but it's cumbersome:

if (!myType.IsValueType)
{
   return null;
}
else
{
   return Activator.CreateInstance(myType);
}

Luckily, value types (including structs) always have a default parameterless constructor. We can't even override it - it will always initialize all struct members to their default values.

This little code snippet can now be wrapper in some sort of function - call it Default() or GetDefault() or even @default() if you want to keep it as close as possible to the generic keyword.

It's interesting to note that the generic keyword relies on the InitObj IL opcode to initialize the object. If we could embed IL directly in our code we could call this directly. We can do it via Reflection.Emit and DynamicMethods but I feel that's going a bit far overboard when the solution above works just as well.

32 Comments

  • Instead of



    int i = default(typeof(int));



    Why don't you use?



    int i = new int();

  • Use default(int) instead of default(typeof(int))



    default(T) takes a type name, not a type value.



    However, this feature is not useful outside generics... because for value types you can use new T() and for reference types, null...

  • Yes, as you can see from the rest of my post this is exactly what I do - I instantiate the value type with the default constructor.



    I'm just saying it would be nicer to have the shorter syntax - default(myType), for instance.

  • You missed my point....

    The feature you requested already exists...

    You typed it wrong.. default(myType) works everywhere. but default(typeof(myType)) works nowhere.

  • Werner - that's exactly my point. I can do default(int) right now, or default(float) or even default(myStruct), but I can't do a default(myRuntimeType). If I received a Type object and want to return that type's default value I have to use the function I outlined above, rather than using a clearer, more concise language construct such as default(type).

  • Dude, I believe that you are totally abusing the default keyword. You should only use it in Generics to assign a default value to your parameterized type. Using it outside generics you should call the constructor of the type as I posted earlier

    int i = new int();
    float f = new float();
    MyObject mo = new MyObject();

  • I think I finally understand what you mean and the answer is no you can't and here is why: you are trying to dynamically create types (thus during runtime) based on another runtime type. You are mixing compile-time with run-time here.

  • Mixing compile-time and run-time is what Reflection is all about. As my sample above shows, I can achieve my goal using Activator.CreateInstance today - I instantiate a new value type at runtime using a type that's unspecified at compile time. What I want is a better way to do what that snippet does - initialize a variable without having to go through its constructor and the Activator methods and everything.

  • It has to do with the type-safety checks in the CLR why this is not allowed. When you use Generics this will be JIT-ted which you still cannot compare with Reflection.

  • Thanks! Needed that little snippet; here's my usage to get some data over ADO.NET:

    // Generic version
    public static T ReadValue(object value)
    {
    return value == DBNull.Value ? default(T) : (T) value;
    }

    // Runtime Type version
    public static object ReadValue(object value, Type targetType)
    {
    object defaultValue = targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
    return ReadValue(value) ?? defaultValue;
    }

  • Thanxs for snippet

  • Resume, mister, which the best solution about this issue ? Greetings

  • Thank Man, That is cool trick for default initialization of object in generic.

  • The is the best solution I have seen to create default value of dynamic type. Awesome!

  • Very nice solution,
    Thanks for sharing.

  • I just happened to need this trick to do myself. Thanks for idea. I wonder, how Activator is internally creating your given value type, and what is the performance cost of that

  • Nice solution. This is also important. when you are doing to IL parsing after return from a method that should contain default value.

  • I solved this issue with an extension method. I put it in a try catch just in case people also try to call the extension from a non-initialized object.

    public static class Extensions
    {
    ///
    /// Determines if a given object is set to its default value or not
    ///
    ///

    ///
    ///
    public static Boolean IsDefaultValue(this T val)
    {
    try
    {
    return ((typeof(T).IsValueType)
    ? (default(T).Equals(val))
    : (null == val));
    }
    catch (NullReferenceException nex)
    {
    return true;
    }
    }
    }

  • Your extention doens't work always.

    Example:
    int i = 0;
    object objectI = i;

    objectI.IsDefaultValue() returns false

    Because the value is compared at the current type (object in this case), not the highest type (int32).

    I changed it to this (it can be shorted but less readable)

    public static Boolean IsDefaultValue(this T val)
    {
    try
    {
    if (val.GetType().IsValueType)
    {
    return (GetDefaultValue(val.GetType()).Equals(val));
    }
    return false;
    }
    catch (NullReferenceException nex)
    {
    return true;
    }
    }

    public static object GetDefaultValue(Type type)
    {
    if (!type.IsValueType) return null;

    object defaultValue;
    lock (DefaultValueTypes)
    {
    if (!DefaultValueTypes.TryGetValue(type, out defaultValue))
    {
    defaultValue = Activator.CreateInstance(type);
    DefaultValueTypes[type] = defaultValue;
    }
    }

    return defaultValue;
    }

  • The reason is that

    default(T) where T is a compile-time type is well understood and T is either defined at compile time or not(which will prevent execution if it is not).

    but default(SomeType) is not well defined at compile time since SomeType, being a type, could be null or anything else. What is default(null)? Remember, default(T) is suppose to always return a correct default at compile time.

    if we have

    int i = default(someType) then what if someType is null? doesn't work does it?

    you cannot do int i = default(float); because the compiler knows the return type of default at compile time and issues an error.

    but when you start doing that kinda stuff at run-time it is no longer a true "default" value and can cause some major bugs.

    even things like

    int i = default(typeof(int)) are problematic for the exact same reasons. How would you solve the problem above if default worked on types?

    int i = default(typeof(int)); // logical by then why not just default(int)???
    int i = default(typeof(someClass)); // no compile time error but surely a runtime error?

    So the real issue is that default(Type) is different than default(T) where T is a generic parameter. default(T) is meant to return a well-defined default value that always works regardless. If you allow default to work on types, e.g., default(type), then you end allow allowing potential bugs in your code.

    If you really want default values then just create an interface and have all your types that need it to implement it.

    say

    interface IDefault
    {
    T Default();
    }

    if you want to also extend Default to built-in types then use extensions.

  • In this case, what can i do?!
    i need default(typeof(myObj.GetType())) works. i Have to much properties and field to clear all one by one.


    public void Dispose()
    {
    foreach (FieldInfo field in
    this.GetType().GetFields(BindingFlags.NonPublic))
    {
    this.GetType().GetField(field.Name).SetValue(this,default((Type)this.GetType().GetField(field.Name).GetType()));
    }
    }

  • Avner is absolutely correct here to complain about this.

    What if you have code that must copy a db field of unknown type to type to some other field whose type is given to you at runtime?

    We can check the db field and if it isn't DBNull we copy it, but if it IS DBNull we cannot, so instead we want to copy the default value for the target type.

    But if the target type's type is only available at runtime, we cannot use the default() keyword can we?





  • Politeness costs nothing and gains everything.

    -----------------------------------

  • -----------------------------------------------------------
    My English communication is not so super butI believe I understand everything. Thank u so much for that fantastic blog publish. I genuinely enjoy studying it. I believe you are a absolute author. At this second additional ur website to my favorites and will appear once more to yor internet web page. Maintain up that wonder perform. Hope to find out more quickly.

  • I prefer to require breaks in the course of the my day and browse by way of some blogs to determine what men and women are talking about. This weblog appeared in my searches and that i could not assist clicking on it. I'm pleased that I did because it was a very intriguing read.

    --------------------------------------------------------------------
    Folklore and Mythology

  • Non_2D00_generic default values in C_23003F00_ Why not_3F002100_.. Super :)

  • Hi there, You have completed an extraordinary job. I will undoubtedly digg it and personally recommend to my buddies. I am sure they are going to be benefited from this web-site.

  • Hey!.... What do you think?

    public static bool IsEmpty(this object value)
    {
    dynamic newInstance = Activator.CreateInstance(value.GetType());

    if (value == null) return true;

    if (value is ValueType)
    {
    return value.Equals(newInstance);
    }
    else
    {
    return value.Equals(newInstance);
    }
    }

  • Pls... just ignore the "if (value is ValueType)"...

  • And now... What do you think...


    public static bool IsEmpty(this object value)
    {

    dynamic newInstance = Activator.CreateInstance(value.GetType());


    if (value == null) return true;


    if (value is IComparable)
    {
    //If the value is an IComparable, and the compare result is 0, then is a default value
    return (newInstance.CompareTo(value) == 0 ? true : false );
    }
    else
    {
    return value.Equals(newInstance);
    }
    }

  • Your question pertains primarily to Types known at compile time. The issue becomes more complex if you want to know the default value of an arbitrary Type at run time.

    Try the following methods, which I have written and tested against thousands of types:

    ///
    /// [ public static T GetDefault< T >() ]
    ///

    /// Retrieves the default value for a given Type
    ///
    /// The Type for which to get the default value
    /// The default value for Type T
    ///
    /// 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.
    ///
    ///
    public static T GetDefault()
    {
    return (T) GetDefault(typeof(T));
    }

    ///
    /// [ public static object GetDefault(Type type) ]
    ///

    /// Retrieves the default value for a given Type
    ///
    /// The Type for which to get the default value

    /// The default value for
    ///
    /// 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.
    ///
    ///
    public static object GetDefault(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 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), 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 (Inner Exception message: \"" + e.Message + "\")", e);
    }
    }

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

    The first (generic) version of GetDefault is of course redundant for C#, since you may just use the default(T) keyword.

    Enjoy!

  • Hi. This blog entry makes you appear heavily misinformed, although to be fair the comments seem to indicate that you do know your stuff, you just haven’t really worded it very well. Here are some corrections:

    • default(T) is *not* for checking if a type is a value type or reference type. It is simply a way of returning a default value (one which, in technical terms, corresponds to binary zeroes).

    • It is not true that default(T) can only be used on generic parameters. You can write default(int) just fine. You refer to it as a “generic keyword” but it has nothing as such to do with generics (any more than typeof() does, anyway).

    • It is true that you can’t use default() on run-time types (variables of type “Type”). It should be quite clear why you can’t do that: the “Type” type is just an API, not really a feature of the C# language. The correct solution would be to have a method in the Reflection API, perhaps Type.GetDefaultValue(), which would do the equivalent of your snippet. I do wonder why such a method doesn’t exist.

    • You correctly discovered that default(T) translates into the IL instruction “initobj”. However, the “initobj” opcode expects a type metadata token as an operand, so you can’t use it on a variable of type “Type”, so it can’t do any more than default(T) can. So being able to embed IL directly into your code wouldn’t help.

Comments have been disabled for this content.