7

我需要编写一堆采用 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;
}
4

4 回答 4

8

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

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

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

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

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

    this.data = new byte[types.Length];
}
于 2013-08-04T16:44:55.800 回答
2

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

于 2013-08-04T16:49:44.730 回答
1

.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 语言能够方便地表达这些概念。闭包可能导致变量的生命周期被任意持久化这一事实意味着曾经在闭包中使用过变量的代码必须假设外部代码可以随时更改它。基于结构的方法不会有这个问题。

于 2013-08-04T21:51:49.413 回答
0

不可以。您不能随意使用 Type 参数。但是你可以使用Tuple 之类的东西。它允许您包装泛型。但是你不能使用 TypeParamter 本身。

于 2013-08-04T16:42:04.837 回答