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

Avner Kashtan said:

If anyone cares about this, you can vote on the language suggestion I opened on Ladybug to extend the default() keyword to all types:
http://lab.msdn.microsoft.com/ProductFeedback/viewFeedback.aspx?feedbackId=FDBK50235
# May 21, 2006 4:22 PM

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

Learn to Speak Korean said:

Good luck getting people today at the rear of this 1.  Although you make some Very fascinating points, youre going to have to do more than carry up a few points that might be distinct than what weve previously heard.  What are attempting to say right here?  What do you want us to assume?  It seems like you cant really get behind a distinctive believed.  Anyway, thats just my view.

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

my website is  

http://signedbaseball.info

Also welcome you!

# December 2, 2010 6:27 AM

ipad app programmers said:

Politeness costs nothing and gains everything.

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

# December 18, 2010 10:18 AM

GetDefaultValue Method (Generic Setting) | ???????????? ???? ???????? said:

Pingback from  GetDefaultValue Method (Generic Setting) | ???????????? ???? ????????

# December 28, 2010 12:10 PM

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

Thorp said:

I love your blog.. very nice colors & theme. Did you

design this website yourself or did you hire someone to do it for you?

Plz reply as I'm looking to design my own blog and would like to find out where u got this from. appreciate it

# March 21, 2013 7:15 PM

Phillips said:

My brother recommended I might like this blog.

He was entirely right. This post actually made my day.

You can not imagine simply how much time I had spent for this

info! Thanks!

# April 10, 2013 9:38 AM

Furr said:

You are so interesting! I do not suppose I've read through anything like that before. So great to find someone with original thoughts on this topic. Really.. many thanks for starting this up. This web site is one thing that's needed

on the web, someone with a little originality!

# April 18, 2013 3:50 AM

Traylor said:

Do you have a spam issue on this site; I also am a blogger, and I was wanting to

know your situation; we have developed some nice practices and we are looking to exchange methods with others, please shoot

me an e-mail if interested.

# April 21, 2013 8:12 PM

Arthur said:

It's a shame you don't have a donate button! I'd most certainly donate to this brilliant blog! I suppose for now i'll settle for bookmarking

and adding your RSS feed to my Google account. I look

forward to fresh updates and will share this site with my Facebook group.

Chat soon!

# April 22, 2013 2:37 PM

Beale said:

I'll right away take hold of your rss feed as I can not find your email subscription link or newsletter service. Do you've

any? Please allow me recognise so that I could subscribe.

Thanks.

# April 22, 2013 3:57 PM

Lauer said:

Ahaa, its good discussion on the topic of this article at this place at this web site, I have read all that, so at this time me also commenting at this place.

# April 23, 2013 12:05 AM

Pride said:

When some one searches for his vital thing, thus he/she wants

to be available that in detail, so that thing is maintained over here.

# April 23, 2013 2:38 AM

Mcmullin said:

Very good post. I'm dealing with some of these issues as well..

# April 23, 2013 2:54 PM

Haight said:

Hi there, I enjoy reading through your article post. I like to write a little

comment to support you.

# April 26, 2013 8:06 AM

Chen said:

Hello there, just became aware of your blog through Google, and found that it's truly informative. I'm gonna

watch out for brussels. I'll be grateful if you continue this in future. Numerous people will be benefited from your writing. Cheers!

# May 2, 2013 3:11 PM

Terry said:

I rarely leave a response, but i did a few

searching and wound up here Non-generic default values in C#?

Why not?! - Miscellaneous Debris. And I do have a

couple of questions for you if you do not mind.

Could it be just me or does it look like some of these comments appear as if they are left

by brain dead folks? :-P And, if you are posting on additional online sites,

I'd like to follow anything fresh you have to post. Could you list of the complete urls of your community sites like your twitter feed, Facebook page or linkedin profile?

# May 7, 2013 2:06 AM

Sprague said:

Thanks for finally talking about >Non-generic default values in C#?

Why not?! - Miscellaneous Debris <Loved it!

# May 8, 2013 3:58 AM

Dowd said:

What i don't realize is if truth be told how you are no longer actually a lot more smartly-appreciated than you might be right now. You are very intelligent. You already know therefore significantly in relation to this matter, produced me personally believe it from so many numerous angles. Its like women and men are not fascinated unless it's something to do with Woman gaga!

Your individual stuffs great. At all times take care of it up!

# May 9, 2013 6:25 AM

Calvin said:

You actually make it seem so easy with your

presentation but I find this topic to be really something which I think I would never understand.

It seems too complex and very broad for me. I am looking forward for

your next post, I will try to get the hang of it!

# May 9, 2013 10:53 AM

Harless said:

I loved as much as you will receive carried out right here.

The sketch is attractive, your authored material

stylish. nonetheless, you command get got an

edginess over that you wish be delivering the following.

unwell unquestionably come more formerly again as exactly the

same nearly a lot often inside case you shield this hike.

# May 9, 2013 5:59 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)