我有以下C#测试代码:
class MyItem
{
MyItem( int a ) {}
}
class MyContainer< T >
where T : MyItem, new()
{
public void CreateItem()
{
T oItem = new T( 10 );
}
}
Visual Studio无法编译它,错误位于使用“new”的位置:
'T': cannot provide arguments when creating an instance of a variable type
在C#中是否可以使用非参数构造函数创建泛型类型的对象?在C ++模板中做这样的事情没有问题,所以我很好奇为什么我不能在C#中做同样的事情。也许还需要一些额外的'where'或语法不同?
答案 0 :(得分:25)
一个解决方法是让调用者在工厂lambda中传递以创建值。例如
public void CreateItem(Func<int,T> del) {
T oItem = del(10);
}
致电网站
CreateItem(x => new SomeClass(x));
答案 1 :(得分:16)
可以用反射来完成:
public void CreateItem()
{
int constructorparm1 = 10;
T oItem = Activator.CreateInstance(typeof(T), constructorparm1) as T;
}
但是没有通用约束来确保T
实现所需的构造函数,所以我不建议这样做,除非你小心地在每个实现的类型中声明构造函数界面。
答案 2 :(得分:9)
没有这样的通用约束,因此不可能直接(这是CLR限制)。如果需要,必须提供工厂类(具有无参数构造函数),并将其作为第二个泛型类型参数传递。
答案 3 :(得分:4)
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);
}
}
但是,您可以使用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);
}
}
请注意,这会缓存并重用代理以提高性能。
答案 4 :(得分:2)
我使用的一种模式是让受约束的类实现一个接口,该接口使用适当的签名定义Init方法:
interface IMyItem
{
void Init(int a);
}
class MyItem : IMyItem
{
MyItem() {}
void Init(int a) { }
}
class MyContainer< T >
where T : MyItem, IMyItem, new()
{
public void CreateItem()
{
T oItem = new T();
oItem.Init( 10 );
}
}