Reputation: 193312
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
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
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
Reputation: 51224
You could use Activator.CreateInstance to create the instance, although it does not do any compile-time checks.
Upvotes: 1
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