Edward Tanguay
Edward Tanguay

Reputation: 193312

What is the syntax to use C# generics as a constructor name?

I've got a number of classes that inherit from Item<T>.

Each class has a Create() method that I would like to move up into Item<T>.

Yet the following code gets the error "Cannot create an instance of the variable type 'T' because it does not have the new() constraint":

T item = new T(loadCode);

What is the correction syntax to do this?

public abstract class Item<T> : ItemBase
{

    public static T Create(string loadCode)
    {
        T item = new T(loadCode);

        if (!item.IsEmpty())
        {
            return item;
        }
        else
        {
            throw new CannotInstantiateException();
        }
    }

Upvotes: 0

Views: 1914

Answers (4)

jerryjvl
jerryjvl

Reputation: 20131

Correction: I made a slight mistake, you need another constraint on T for this solution, see code below.

You can only put a constraint on for parameterless constructor, but maybe something like this could work:

public interface ILoadable
{
    void Load(string loadCode);
}

public abstract class Item<T> : ItemBase
    where T : ILoadable, new()
{
    public static T Create(string loadCode)
    {
        T item = new T();
        item.Load(loadCode);

        if (!item.IsEmpty())
        {
            return item;
        }
        else
        {
            throw new CannotInstantiateException();
        }
    }
}

And then you implement the constructor code that depends on the loadCode in the override to Load(...) in the descendant classes.

Upvotes: 3

samjudson
samjudson

Reputation: 56853

The error is because the compiler cannot rely on the fact that the generic class T has anything other than the default constructor.

You can overcome this using reflection as follows:

ConstructorInfo c = typeof(T).GetConstructor(new Type[] { typeof(string) });
T t = (T)c.Invoke(new object[] { loadCode });

As your T type must therefore have a constructor which takes a string then I would also restrict your class so that it must inherit from a class with a constructor:

class Item<T> : ItemBase where T : BaseClassWithConstructor

Upvotes: 1

vgru
vgru

Reputation: 51224

You could use Activator.CreateInstance to create the instance, although it does not do any compile-time checks.

Upvotes: 1

Mehrdad Afshari
Mehrdad Afshari

Reputation: 422006

It's not possible. You can only use new() constraint to force existence of a constructor.

A workaround is to take a Func<InputType, T> (Func<string,T> in your example) delegate as input parameter that'll create the object for us.

public static T Create(string loadCode, Func<string,T> construct)
{
    T item = construct(loadCode);

    if (!item.IsEmpty())
    {
        return item;
    }
    else
    {
        throw new CannotInstantiateException();
    }
}

and call it with: Item<T>.Create("test", s => new T(s));

Upvotes: 9

Related Questions