我有许多继承自Item<T>
的课程。
每个类都有一个Create()方法,我希望将其移至Item<T>
。
然而下面的代码得到错误“无法创建变量类型'T'的实例,因为它没有new()约束”:
T item = new T(loadCode);
执行此操作的更正语法是什么?
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();
}
}
答案 0 :(得分:9)
这是不可能的。您只能使用new()
约束来强制存在构造函数。
解决方法是将Func<InputType, T>
(示例中为Func<string,T>
)委托作为输入参数,为我们创建对象。
public static T Create(string loadCode, Func<string,T> construct)
{
T item = construct(loadCode);
if (!item.IsEmpty())
{
return item;
}
else
{
throw new CannotInstantiateException();
}
}
并使用:Item<T>.Create("test", s => new T(s));
答案 1 :(得分:3)
更正:我犯了一个小错误,此解决方案需要T的另一个约束,请参阅下面的代码。
你只能为无参数构造函数设置一个约束,但也许这样的东西可以工作:
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();
}
}
}
然后实现构造函数代码,该代码依赖于后代类中loadCode
覆盖中的Load(...)
。
答案 2 :(得分:1)
您可以使用Activator.CreateInstance创建实例,但它不会进行任何编译时检查。
答案 3 :(得分:1)
错误是因为编译器不能依赖泛型类T具有除默认构造函数之外的任何事实。
您可以使用反射来解决此问题,如下所示:
ConstructorInfo c = typeof(T).GetConstructor(new Type[] { typeof(string) });
T t = (T)c.Invoke(new object[] { loadCode });
因为你的T类型必须有一个构造函数,它接受一个字符串然后我也会限制你的类,以便它必须从一个带有构造函数的类继承:
class Item<T> : ItemBase where T : BaseClassWithConstructor