C#:具有构造函数的泛型类型?

gri*_*yvp 19 c# generics

我有以下C#测试代码:

  class MyItem
  {
    MyItem( int a ) {}
  }

  class MyContainer< T >
    where T : MyItem, new()
  {
    public void CreateItem()
    {
      T oItem = new T( 10 );
    }
  }
Run Code Online (Sandbox Code Playgroud)

Visual Studio无法编译它,错误在使用'new'的位置:

'T': cannot provide arguments when creating an instance of a variable type
Run Code Online (Sandbox Code Playgroud)

在C#中是否可以使用非参数构造函数创建泛型类型的对象?在C++模板中做这样的事情没有问题,所以我很好奇为什么我不能在C#中做同样的事情.也许还需要一些额外的'where'或语法不同?

Jar*_*Par 25

对于这个问题,C#和VB.Net不支持将泛型约束为具有特定参数的构造函数的概念.它只支持约束有一个空构造函数.

一种解决方法是让调用者在工厂lambda中传递以创建值.例如

public void CreateItem(Func<int,T> del) {
  T oItem = del(10);
}
Run Code Online (Sandbox Code Playgroud)

致电网站

CreateItem(x => new SomeClass(x));
Run Code Online (Sandbox Code Playgroud)


Gre*_*reg 16

它可以通过反射来完成:

public void CreateItem()
{
  int constructorparm1 = 10;
  T oItem = Activator.CreateInstance(typeof(T), constructorparm1) as T;
}
Run Code Online (Sandbox Code Playgroud)

但是没有通用约束来确保T实现所需的构造函数,所以除非你小心地在每个实现接口的类型中声明构造函数,否则我不建议这样做.


Pav*_*aev 9

没有这样的通用约束,因此不可能直接(这是CLR限制).如果需要,则必须提供工厂类(具有无参数构造函数),并将其作为第二个泛型类型参数传递.


Mar*_*ell 5

IMO,这里最好的方法是初始化方法,即

interface ISomeInterface {
    void Init(int i);
}
class Foo : ISomeInterface {
    void ISomeInterface.Init(int i) { /* ... */ }
}
static class Program {
    static T Create<T>(int i) where T : class, ISomeInterface, new() {
        T t = new T();
        t.Init(i);
        return t;
    }
    static void Main() {
        Foo foo = Create<Foo>(123);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,您可以执行您想要的操作Expression(但没有编译时支持):

using System;
using System.Linq.Expressions;
class Foo {
    public Foo(int i) { /* ... */ }
}
static class Program {
    static T Create<T>(int i) {
        return CtorCache<T>.Create(i);
    }
    static class CtorCache<T> {
        static Func<int, T> ctor;
        public static T Create(int i) {
            if (ctor == null) ctor = CreateCtor();
            return ctor(i);
        }
        static Func<int, T> CreateCtor() {
            var param = Expression.Parameter(typeof(int), "i");
            var ci = typeof(T).GetConstructor(new[] {typeof(int)});
            if(ci == null) throw new InvalidOperationException("No such ctor");
            var body = Expression.New(ci, param);
            return Expression.Lambda<Func<int, T>>(body, param).Compile();
        }
    }
    static void Main() {
        Foo foo = Create<Foo>(123);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这会缓存并重用委托以提高性能。