参考该问题:Cannot create an instance of the variable type 'Item' because it does not have the new() constraint
我想使用非空构造函数从泛型类型创建实例。
public class A{};
public class B
{
public B(int){/*...*/}
}
public class C
{
public static T validate<T>(int index)
where T : A,
new(int) //error
{
if(/*validation*/)
return null;
return new T(index);
}
}
如果我尝试拨打B b = validate<B>(42);
,我收到此错误:
&#39; B&#39;必须是具有公共无参数构造函数的非抽象类型才能将其用作参数&#39; T&#39;通用类型或方法&#39; C.validate(int)&#39;
问题1 :为什么我只能使用无参数构造函数?
问题2 :如果没有代理或接口,如何解决我的问题? (我一直在寻找花哨的解决方案。)
答案 0 :(得分:3)
您可以使用反射来调用构造函数:
var constructorInfo = typeof(T).GetConstructor(new[] { typeof(int) });
if (constructorInfo != null)
{
object[] parameters = new object[] { index };
return (T)constructorInfo.Invoke(parameters);
}
else
{
// handle it
}
(改编自https://stackoverflow.com/a/13523659/5962841)
或者,您可以使用激活器创建实例(请参阅@ datrax的回答)
(T)Activator.CreateInstance(typeof(T), index)
您经常要求提供您要求的功能。
此处正在跟踪此功能的请求(github csharp design repo),但今年并未预料到它,甚至没有原型或接受。
答案 1 :(得分:2)
这里的问题并不适合C#generics。
泛型类型应该具有公共接口,就属性和属性而言。方法,这是指定T的全部要点必须是A的实例或A的子类。
这里,A没有int构造函数,但是你想创建一个具有int构造函数的子类的实例。
此外,从您的代码中,B不从A继承,但您在泛型方法中指定了T:A。这只是一种疏忽吗?
使用Activator也依赖于后期绑定,所以如果你为一个没有适当构造函数的类调用它,你将会遇到运行时错误。
功能方法更直观,看起来更干净,并且不依赖于运行时反射。
public class A {
};
public class B:A
{
public B(int y){ x = y; }
public int x { get; }
}
public class C
{
public static T validate<T>(int index, Func<int, T> instantiator)
where T : A
{
if (false)
return null;
return instantiator(index);
}
}
class Program
{
static void Main(string[] args)
{
B b = C.validate<B>(42, (y)=>new B(y));
}
}
答案 2 :(得分:1)
不允许将任何参数传递给泛型类型的构造函数。唯一可能的约束是:其中T:new()。 但无论如何,仍然有可能创建这样的实例
(T)Activator.CreateInstance(typeof(T), index);