C#泛型:将泛型参数类型引用为集合的任何方式

本文关键字:泛型 任何方 何方 参数 类型 引用 集合 | 更新日期: 2023-09-27 18:26:14

我需要写一堆采用1..N泛型类型参数的方法,例如:

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

Foo()内部,我想为每种类型做点什么,例如

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

有没有什么方法可以参数化它,这样我就不会编辑Foo()的每一个变体,类似于:

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

理想情况下,我还希望能够获得一个数组或类型的集合:

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;
}

C#泛型:将泛型参数类型引用为集合的任何方式

您可以从MethodInfo.GetGenericArguments数组中读取当前的泛型参数及其编号。

您可以使用MethodBase.GetCurrentMethod方法检索当前方法的MethodInfo

请注意,您仍然需要为方法提供几个具有不同数量的通用参数的通用重载,因为C#和CLI不支持可变的通用参数列表。

因此,具有三个通用参数的方法的代码示例可以这样写:

int Foo<T1,T2,T3>() {
    MethodInfo mInfo = (MethodInfo)MethodBase.GetCurrentMethod();
    Type[] types = mInfo.GetGenericArguments();
    this.data = new byte[types.Length];
}

1)您可以通过反射获得模板参数的数量:http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx。通过这种方式,您可以为每个Foo提供通用的实现。在每个Foo中,您只需拨打:

FooImpl();

唯一的区别(关于"GetCurrentMethod")是,您需要获得上一个方法的方法信息:

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

2) 您可以在运行时生成所有Foo版本——所有版本都共享相同的实现,只调用FooImpl。关于在运行时生成方法的一些详细信息:在运行时动态创建函数,如下所示:http://msdn.microsoft.com/en-us/library/exczf7b9.aspx

.NET框架将具有N个类型参数的泛型类或方法视为具有与具有更多或更少类型参数的类或方法不同的名称。在没有对框架进行巨大更改的情况下,可能会安排一些事情,以便调用函数

foo<T>(autogeneric ref T it)

作为:

foo(1, "George", 5.7);

将被翻译为:

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);

这将允许通用方法有效地接受任意数量的参数。能够通过ref传递这样的匿名结构似乎不是很有用,但当与lambdas结合时,它可能会非常强大。

通常,关闭lambda表达式中的局部变量需要将局部变量提升到堆对象,并构建一个以该堆对象为目标的委托。如果可以使用上面的样式,那么可以不创建持久闭包对象和委托并传递委托,而只需将适当的变量提升到一个结构中,并将byref和静态委托一起传递给它。这只适用于被调用例程不必持久化传入的闭包的情况,但另一方面,调用者会知道被调用例程不会持久化闭包。此外,虽然没有.NET语言会支持这样的东西,并且可能需要一些框架更改来允许这样做的代码是不稳定的,通过引用传递一个结构(其中一些成员也是byrefs),可以使lambda访问封闭过程的ref参数——这是目前不可能的(因为无法保证创建的委托不会超过创建它的范围)。当结构所处的范围消失时,它们就会消失,所以问题就不必存在了。

我希望.NET语言有一种方便的方式来表达这些概念。闭包可能导致变量的生存期被任意持久化,这意味着在闭包中使用过变量的代码必须假设外部代码可以随时更改它。基于结构的方法不会有这个问题。

否。不能根据需要使用Type参数。但你可以用类似Tuple的东西。它允许你包装泛型。但是您不能使用TypeParamter本身。