使用C#Generics从方法创建通用对象(不是“new”)

时间:2012-08-01 16:00:02

标签: c# generics

我习惯使用C ++模板,并意识到C#中的工作方式略有不同。这就是我想要的:

    T CreateButton<T>() {
       T test = T.create(...some vars...);
       return test;
    }

我认为可能使用带有基类的派生约束,该基类具有定义的“create”方法,但它仍然无法编译。

我收到此编译错误:**error CS0119: Expression denotes a 'type parameter', where a 'variable', 'value' or 'type' was expected**

有没有办法完成我在C#中尝试做的事情?

5 个答案:

答案 0 :(得分:4)

你的问题是你正在调用T.Create,好像它是泛型T上的静态方法。这带来了两个问题 - 首先,你不能继承静态(你必须做的就是限制它的类型) T到定义'静态创建'的基类,以便T.Create编译)。其次,即使你可以继承一个静态,基类.Create()也必须“知道”才能返回一个T。

你在这里的是工厂。定义一个充当T的工厂的类,然后你可以写

T test = Factory&lt; T&gt; .Create(...... some vars ...);

这感觉就像它会导致巨大的切换声明 - 基于真实类型的T做正确的事情。但这是控制反转和依赖注入可以帮助你的地方。为每种类型的T定义一个带有“插件”的工厂。使用IoC将插件注入工厂。

查看讨论here

答案 1 :(得分:2)

这应该是你想要的:

class MyFactory<T> where T : new()
{
    public T CreateMyStuff()
    {
        return new T();
    }
}

答案 2 :(得分:0)

您必须定义和实现接口(或基类)。您还必须约束new()。然后你可以对它使用泛型约束。

您无法针对通用参数调用静态方法。 I.E。:您无法在T上调用静态方法。

答案 3 :(得分:0)

问题出在特定行T.Create(...)

T是一个Type,而不是一个变量,所以除非Create()方法是该类型的静态方法,否则它不会编译,即使那时T也不知道创建实际是什么,所以你不能编译函数调用以开始。如果以某种方式约束T以使代码知道Create()函数存在,则可以执行此操作。

示例

假设T将始终是某个Base类的成员或继承成员,该函数将声明如下:

T CreateButton<T>() where T : BusinessObjectBase
{
   T test = (T)BusinessObjectBase.create(...some vars...);
   return test;
}

在这种情况下,静态函数Create()在BusinessObjectBase中声明,并且作为T传入的类型被约束为该类或从该类扩展,从而保证T能够调用的代码Create()函数。

当然,正如其他人所提到的,使用new()约束要容易得多。这允许您简单地返回新的T();远不那么复杂,但是你会失去创建函数中那些参数。

答案 4 :(得分:0)

除了满足new约束的类型之外,没有办法创建泛型类型的新对象,只给出类型。相反,您最好的选择可能是让需要创建事物的方法接受适合该任务的委托。

// Suppose you need to be able to create things whose constructors should take
//  an Int32.  Then do something like:

void MakeLotsOfTs<T>(Func<Int32, T> CreationProc) // And whatever other stuff you want
{
  ... whenever you need a new T for a given integer N, call CreationProc(N)
}

如果您有一个类Foo,其构造函数需要Int32,并且您希望将其传递给 以上方法,使用方法

  MakeLotsOfTs<Foo>( (Int32 param) => new Foo(param) );

Note that this approach will work even if you want to use it with a class whose constructor requires something else (e.g. one could do something like:

MakeLotsOfTs<Bar>( (Int32 param) => new Bar(String.Format("Bar #{0}", param)) );

这种方法需要为调用者多做一些工作,而不是指定一个&#34;参数化&#34; new约束,但更强大。