简体   繁体   English

使用C#泛型从方法(不是“新”)创建泛型对象

[英]Using C# Generics to create a generic object from a method (not “new”)

I'm used to C++ templates and realize that things work a little differently in C#. 我习惯了C ++模板,并意识到在C#中工作原理有些不同。 Here's what I want: 这就是我想要的:

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

I thought maybe using a derivative constraint with a base class that has the "create" method defined would do the trick but it still won't compile. 我以为也许在定义了“创建”方法的基类中使用派生约束可以解决问题,但仍然无法编译。

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

Is there a way to accomplish what I'm trying to do in C#? 有没有一种方法可以完成我在C#中要做的事情?

Your problem is that you're calling T.Create as if it were a static method on the generic T. That poses two problems - first, you cannot inherit statics (which you'd have to do to restrict the type of T to a base-class that defined 'static Create' so that T.Create would compile). 您的问题是您正在调用T.Create,就好像它是通用T上的静态方法一样。这带来了两个问题-首先,您无法继承静态变量(必须这样做才能将T的类型限制为定义“静态创建”的基本类,以便T.Create进行编译)。 Second, even if you could inherit a static, somehow the base class .Create() would have to 'know' to return a T. 其次,即使您可以继承静态方法,基类.Create()也必须以某种方式“知道”返回T。

What you're after here is a Factory. 您在这里追求的是一家工厂。 Define a class that acts as a factory for T's, Then you can write 定义一个充当T工厂的类,然后您可以编写

T test = Factory < T >.Create(... some vars ...); T test = Factory <T> .Create(...一些变量...);

This feels like it would result in a giant switch statement of sorts - based on the real type of T do the right thing. 感觉这会导致巨大的switch语句-基于T的真实类型做正确的事情。 But this is where inversion-of-control and dependency-injection can help you. 但这是控制反转和依赖注入可以为您提供帮助的地方。 Define a Factory with 'plug-ins' for each type of T you need. 为您需要的每种T类型定义一个带有“插件”的工厂。 Use IoC to inject the plug-ins into your factory. 使用IoC将插件注入您的工厂。

Check out the discussion here 这里查看讨论

This should be what you're after: 这应该是您所追求的:

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

You have to define and implement an interface (or a base class). 您必须定义和实现接口(或基类)。 You will also have to constrain for new() . 您还必须约束new() Then you can use generic constraints on it. 然后,您可以对其使用通用约束。

You can't call static methods against a generic parameter. 您不能针对通用参数调用静态方法。 IE: You can't call a static method on T . IE:您无法在T上调用静态方法。

The issue is with the specific line T.Create(...) 问题在于特定行T.Create(...)

T is a Type, not a variable, so unless the Create() method is a static method of the type, then it wont compile, and even then T doesn't know what create actually is, so you wont be able to compile the function call to begin with. T是一个Type,而不是变量,因此,除非Create()方法是该类型的静态方法,否则它将无法编译,即使T也不知道create的真正含义,因此您将无法编译函数调用从此开始。 If you constrain T in some manner so that the code knows that the Create() function exists, then you can do this. 如果以某种方式约束T,以使代码知道存在Create()函数,则可以执行此操作。

Example

Assume T will always be a member or inherited member of some Base class, the function would be declared as follows: 假设T将始终是某个Base类的成员或继承的成员,则该函数将声明如下:

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

In this case, the static function Create() is declared inside the BusinessObjectBase, and the type passed in as T is constrained to be, or be extended from, that class, guaranteeing the code that T will be able to call the Create() function. 在这种情况下,静态函数Create()在BusinessObjectBase内部声明,并且作为T传入的类型被约束为该类或从该类扩展,从而保证T能够调用Create()的代码。功能。

Of course, as others have mentioned, its far easier to use the new() constraint. 当然,正如其他人提到的那样,使用new()约束要容易得多。 This allows you to simply return new T(); 这使您可以简单地返回新的T();。 far less complex, but you lose whatever those parameters were from the create function. 复杂程度要低得多,但是您会丢失create函数中的那些参数。

With the exception of types which satisfy a new constraint, there is no way to create a new object of generic type, given nothing but the type. 除了满足new约束的类型外,没有任何方法可以创建泛型的新对象,仅提供类型即可。 Instead, your best bet is probably to have the method which needs to create the things accept a delegate suitable for the task. 相反,最好的选择可能是让需要创建事物的方法接受适合该任务的委托。

// 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)
}

If you have a class Foo whose constructor takes an Int32 , and you wish to pass it to the above method, use 如果您有一个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)) );

This approach requires a little more work for the caller than would being able to specify a "parameterized" new constraint, but is much more powerful. 与能够指定“参数化” new约束相比,此方法对调用者的工作量更多,但是功能更强大。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM