使用非空构造函数初始化泛型类型

时间:2017-07-28 09:53:57

标签: c# generics compiler-errors

参考该问题: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 :如果没有代理或接口,如何解决我的问题? (我一直在寻找花哨的解决方案。)

3 个答案:

答案 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);