4

I have a class which pulls objects from Isolated Storage. If it cannot find the object in question it returns default(T) which would be null as they are reference types. If the value returned is null I do a simple check and assign a new instance in the caller but I would prefer to do this in the storage logic.

So my question, is there a way to return a new T where the object has a default blank constructor?

deanvmc
  • 5,957
  • 6
  • 38
  • 68
  • possible duplicate of [Creating a nullable object via Activator.CreateInstance returns null](http://stackoverflow.com/questions/8691601/creating-a-nullable-object-via-activator-createinstance-returns-null) – nawfal Apr 25 '13 at 12:17

5 Answers5

15

An option would be use the contraint "new": http://msdn.microsoft.com/en-us/library/sd2w2ew5(v=vs.80).aspx

Like so:

public T GetNewItem()
    where T: new()
{
    return new T();
}

But having this constraint means that you can't use a type that doesn't have a default constructor. So you may consider to use System.Activator.CreateInstance, but remember that it may throw an exception:

T createInstance<T>()
{
    try
    {
        return System.Activator.CreateInstance<T>();
    }
    catch (MissingMethodException exc)
    {
        return default(T);
    }
}

So, it may be a good idea to know if the given type supports this early in the initialization, a way to do so follows:

T createInstance<T>()
{
    System.Reflection.ConstructorInfo constructor = (typeof(T)).GetConstructor(System.Type.EmptyTypes);
    if (ReferenceEquals(constructor, null))
    {
        //there is no default constructor
        return default(T);
    }
    else
    {
        //there is a default constructor
        //you can invoke it like so:
        return (T)constructor.Invoke(new object[0]);
        //return constructor.Invoke(new object[0]) as T; //If T is class
    }
}

While you are at it, why not get a delegate that creates an instance?

Func<T> getConstructor<T>()
{
    System.Reflection.ConstructorInfo constructor = (typeof(T)).GetConstructor(System.Type.EmptyTypes);
    if (ReferenceEquals(constructor, null))
    {
        return () => { return default(T); };
    }
    else
    {
        return () => { return (T)constructor.Invoke(new object[0]); };
    }
}

An example of how to use it (compiled with LinqPad):

void Main()
{
    Console.WriteLine(getConstructor<object>()());
    Console.WriteLine(getConstructor<int>()());
    Console.WriteLine(getConstructor<string>()());
    Console.WriteLine(getConstructor<decimal>()());
    Console.WriteLine(getConstructor<DateTime>()());
    Console.WriteLine(getConstructor<int?>()());
}

The output is:

System.Object
0
null
0
01/01/0001 12:00:00 a.m.
null

The case of string is a special case, being a referece type it can be null, and not having a public default constructor that's what you get here instead of String.Empty. The nullable type also gives null.

Theraot
  • 31,890
  • 5
  • 57
  • 86
3

You can add a constraint to your type parameter, but that will preclude any classes that don't support an empty-argument constructor from being used as the type argument.

public class Foo<T> where T : new()
{
    // Now you can say T blah = new T();
}

You can also call Activator.CreateInstance<T>(), but that will throw if the type doesn't have the right constructor.

I think you might be better off documenting that your method returns null if the object can't be found, and letting the calling code handle that condition as it sees fit. It will be in the best position to know how to proceed.

dlev
  • 48,024
  • 5
  • 125
  • 132
2

Add the new() constraint to your generic method:

public T Create<T>() where T: class, new()
{
  return new T();
}
Femaref
  • 60,705
  • 7
  • 138
  • 176
1

This works:

using System;

public class Test
{
    static T CreateT<T>(bool _new) where T: new()
    {
        if (_new) return new T(); else return default(T);
    }
    public static void Main()
    {
        var o = CreateT<object>(true);
    }
}
Vlad
  • 35,022
  • 6
  • 77
  • 199
0

From Generic method to instantiate a variable of any type (including nullable struct)?

public static T GetEmpty<T>() where T : new() //this constraint is important
{
    return (T)Activator.CreateInstance(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T));
}

This works for nullable structs as well. For int?, it returns 0 and not null. Faster approaches here.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368