views:

240

answers:

5

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.

+3  A: 

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 Einstein
+1 thats a nice example but actually I don't need that much.
viky
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?
+16  A: 

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);
    } else {
        return null;
    }
}

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

Dean Harding
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 Einstein
@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
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.
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
@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 Einstein
+2  A: 

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

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

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