Miscellaneous Debris

Avner Kashtan's Frustrations and Exultations

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.

Comments

Gabriel Lozano-Morán said:

Instead of

int i = default(typeof(int));

Why don't you use?

int i = new int();
# May 21, 2006 8:33 AM

Wesner Moise said:

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...
# May 21, 2006 9:05 AM

Avner Kashtan said:

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.
# May 21, 2006 9:45 AM

Wesner Moise said:

You missed my point....

The feature you requested already exists...

You typed it wrong.. default(myType) works everywhere. but default(typeof(myType)) works nowhere.
# May 22, 2006 7:40 PM

AvnerK said:

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).
# May 23, 2006 3:00 AM

Gabriel Lozano-Morán said:

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();
# May 24, 2006 6:13 PM

Gabriel said:

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.
# May 24, 2006 8:27 PM

Avner Kashtan said:

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.
# May 24, 2006 11:46 PM

Gabriel said:

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.
# May 25, 2006 8:25 AM

Jacob said:

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

// Generic version

public static T ReadValue<T>(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<object>(value) ?? defaultValue;

}

# September 12, 2006 2:46 PM

Rene Dohan said:

Thanxs for snippet

# October 1, 2006 2:39 PM

espinete said:

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

# February 8, 2008 6:52 AM

Amber said:

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

# February 12, 2008 10:22 AM

Jason said:

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

# March 21, 2008 7:12 AM

Miron said:

Very nice solution,

Thanks for sharing.

# June 18, 2008 11:36 PM

Darius Damalakas said:

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

# March 5, 2009 1:57 AM

mehfuzh said:

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

# October 22, 2009 4:22 AM

Charles T. said:

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

   {

       /// <summary>

       /// Determines if a given object is set to its default value or not

       /// </summary>

       /// <param name="obj"></param>

       /// <returns></returns>

       ///

       public static Boolean IsDefaultValue<T>(this T val)

       {

           try

           {

               return ((typeof(T).IsValueType)

                           ? (default(T).Equals(val))

                           : (null == val));

           }

           catch (NullReferenceException nex)

           {

               return true;

           }

       }

   }

# November 19, 2009 1:18 PM

Job Vermeulen said:

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<T>(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;

     }

# March 19, 2010 5:03 AM

Jo said:

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>

{

  T Default();

}

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

# August 22, 2010 4:15 AM

Guilherme Coelho said:

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()));

       }

   }

# October 21, 2010 10:12 AM

Dirty Harry said:

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?

# October 22, 2010 9:12 PM

ipad app programmers said:

Politeness costs nothing and gains everything.

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

# December 18, 2010 10:18 AM

ipad reviews said:

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

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.

# January 8, 2011 6:58 AM

cordless phones reviews said:

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

# January 17, 2011 7:34 AM

weblogs.asp.net said:

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

# May 18, 2011 8:10 PM

Vivienne Mikhail said:

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.

# June 30, 2011 7:58 PM

Marcos Lima said:

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

           }

       }

# October 10, 2011 10:50 AM

Marcos Lima said:

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

# October 10, 2011 10:54 AM

Marcos Lima said:

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

           }

       }

# October 10, 2011 11:02 AM

Mark Jones said:

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:

       /// <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));

       }

       /// <summary>

       /// [ <c>public static object GetDefault(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>

       /// <seealso cref="GetDefault&lt;T&gt;"/>

       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 <" + 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 <" + 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");

       }

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

Enjoy!

# October 23, 2011 5:38 PM

Timwi said:

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.

# February 8, 2012 2:10 PM