[英]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将插件注入您的工厂。
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.