简体   繁体   English

C#泛型:任何方式将泛型参数类型称为集合?

[英]C# generics: any way to refer to the generic parameter types as a collection?

I need to write a bunch of methods that take 1..N generic type parameters, eg: 我需要编写一堆采用1..N泛型类型参数的方法,例如:

int Foo<T1>();
int Foo<T1,T2>();
int Foo<T1,T2,T3>();
...
int Foo<T1,T2,T3...TN>();

Inside Foo() I would like to do something for each type, eg Foo()里面,我想为每种类型做一些事情,例如

int Foo<T1,T2,T3>() {
    this.data = new byte[3]; // allocate 1 array slot per type
}

Is there any way to parameterize this so that I am not editing every variation of Foo() , something analogous to: 有没有办法参数化这个,所以我不编辑Foo()每个变体,类似于:

int Foo<T1,T2,T3>() {
    this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];
}

Ideally, I'd also like to be able to get an array or collection of the types as well: 理想情况下,我也希望能够获得一个数组或类型的集合:

int Foo<T1,T2,T3>() {
    this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];

    // can do this
    Type [] types = new Type[] { T1, T2, T3 };
    // but would rather do this
    Type [] types = _ARRAY_OR_COLLECTION_OF_THE_GENERIC_PARAMETERS;
}

You can read the current generic parameters and their number from the MethodInfo.GetGenericArguments array . 您可以从MethodInfo.GetGenericArguments数组中读取当前通用参数及其编号。

You can retrieve the MethodInfo for your current method by using the MethodBase.GetCurrentMethod method . 您可以使用MethodBase.GetCurrentMethod方法检索当前方法的MethodInfo

Note that you will still need to supply several generic overloads of your method with different numbers of generic parameters, as C# and the CLI do not support variadic generic parameter lists. 请注意,由于C#和CLI不支持可变参数通用参数列表,因此仍需要使用不同数量的通用参数提供方法的几个泛型重载。

So, your code sample for the method with three generic parameters could be written like this: 因此,具有三个通用参数的方法的代码示例可以这样写:

int Foo<T1,T2,T3>() {
    MethodInfo mInfo = (MethodInfo)MethodBase.GetCurrentMethod();
    Type[] types = mInfo.GetGenericArguments();

    this.data = new byte[types.Length];
}

1) You can get the number of template arguments via reflection: http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx . 1)您可以通过反射获取模板参数的数量: http//msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx This way, you can have common implementation for each Foo. 这样,您就可以为每个Foo实现通用实现。 In each Foo you can just call: 在每个Foo中你可以打电话:

FooImpl();

The only difference (regarding the "GetCurrentMethod") is that you'll need to get method info of the previous method: 唯一的区别(关于“GetCurrentMethod”)是你需要获取前一个方法的方法信息:

StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();

2) You could generate all Foo versions at runtime - all would share the same implementation of calling FooImpl only. 2)您可以在运行时生成所有Foo版本 - 所有版本都将共享调用FooImpl的相同实现。 Some details on generating methods at runtime: Creating a function dynamically at run-time and here: http://msdn.microsoft.com/en-us/library/exczf7b9.aspx 有关在运行时生成方法的一些细节:在运行时动态创建函数 ,请访问: http//msdn.microsoft.com/en-us/library/exczf7b9.aspx

The .NET framework regards a generic class or method with N type parameters as having a different name from one having more or fewer. .NET框架将具有N类型参数的泛型类或方法视为具有与具有更多或更少的名称不同的名称。 It would probably be possible without a huge change to the framework to arrange things so that calling a function 如果没有对框架进行大的改动就可以安排事情以便调用函数

foo<T>(autogeneric ref T it)

as: 如:

foo(1, "George", 5.7);

would get translated as to: 将被翻译为:

struct foo99 {public int p1; public string p2; public double p3};
...
foo99 temp99;
temp99.p1 = 1;
temp99.p2 = "George";
temp99.p3 = 5.7;
foo1(ref temp);

That would allow a generic method to efficiently accept an arbitrary number of parameters. 这将允许通用方法有效地接受任意数量的参数。 Being able to pass such anonymous structure by ref might not seem terribly useful, but it could be very powerful when combined with lambdas. 能够通过ref传递这样的匿名结构可能看起来并不十分有用,但是当与lambdas结合使用时它可能非常强大。

Normally, closing over local variables in a lambda expression would require hoisting the local variables to a heap object and building a delegate which targets that heap object. 通常,关闭lambda表达式中的局部变量需要将局部变量提升到堆对象并构建一个以该堆对象为目标的委托。 If one could use the above style, one could instead of creating a persistent closure object and a delegate and passing the delegate, simply hoist the appropriate variables to a structure and pass a byref to it along with a static delegate. 如果可以使用上述样式,则可以代替创建持久闭包对象和委托并传递委托,只需将适当的变量提升到结构并将一个byref与静态委托一起传递给它。 This would only work in cases where the called routine wouldn't have to persist the passed-in closure, but on the flip side the caller would know that the called routine wouldn't be persisting the closure. 这只适用于被调用的例程不必持久传递闭包的情况,但在另一方面,调用者会知道被调用的例程不会持久化闭包。 Further, while no .NET languages would support such a thing and some framework changes might be required to allow code which did this to be volatile, passing by reference a structure some of whose members were also byrefs could make it possible for a lambda to access the enclosing procedure's ref parameters--something which is presently not possible (since there's no guarantee the created delegate wouldn't outlive the scope where it was created). 此外,虽然没有.NET语言会支持这样的事情,并且可能需要进行一些框架更改以允许执行此操作的代码是易变的,通过引用传递一个结构,其中一些成员也是byrefs可以使lambda可以访问封闭过程的ref参数 - 目前不可能的(因为不能保证创建的委托不会比创建它的范围更长)。 Structures die when the scope they're in dies, so the problem wouldn't have to exist with them. 结构在它们所处的范围死亡时死亡,因此问题不一定存在。

I wish .NET languages had a convenient way of expressing these concepts. 我希望.NET语言有一种表达这些概念的便捷方式。 The fact that closures can cause variables' lifetimes to be arbitrarily persisted means that code which has ever used a variable in a closure must assume that outside code could change it at any time. 闭包可以导致变量的生命周期被任意持久化的事实意味着在闭包中曾经使用过变量的代码必须假设外部代码可以随时改变它。 A struct-based approach wouldn't have that issue. 基于结构的方法不会有这个问题。

No. You can not use the Type parameter as you want. 不能。您不能根据需要使用Type参数。 But you could use something like Tuple . 但你可以使用像Tuple这样的东西。 It allows you to Wrap generics. 它允许你包装泛型。 But you can not use the TypeParamter itself. 但是你不能使用TypeParamter本身。

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

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