如何创建具有指定泛型类型的函数类型?

4
我想创建指定范型类型参数的 Func 类型,类似于以下代码,但只使用一条语句。
Type create_type(Type[] types)
{
   return typeof(Func<>).MakeGenericType(types); // error if types.Length != 1
   return typeof(Func<,>).MakeGenericType(types); // error if types.Length != 2
   return typeof(Func<,,>).MakeGenericType(types); // error if types.Length != 3
   return typeof(Func<,,,>).MakeGenericType(types); // error if types.Length != 4
// .... 
}

当然,我可以创建辅助数组:
var func_types = new Type[] { typeof(Func<>), typeof(Func<,>) , //...}

但是这个解决方案对我来说看起来太丑陋了。

注意:类型数组可能很长(最多达到15个),我想找到一个优雅的解决方案。不幸的是,我正在从另一种语言编写的元数据中创建这样的类型。

2个回答

12

Expression类中有静态方法可用于Func和Action,这些方法正是您所需的。

Expression.GetFuncType(Type[] types)

Expression.GetActionType(Type[] types)

更多信息请参见:

GetFuncType

GetActionType


那是一个很棒的答案! - Alex Aparin
2
那么我撤回我之前关于需要丑陋代码的评论 :) 原来问题只是谁将不得不编写那些丑陋或复杂的代码 - https://referencesource.microsoft.com/#System.Core/Microsoft/Scripting/Compiler/DelegateHelpers.Generated.cs,227 - Lasse V. Karlsen
@CSharpie,是否有元组类型的类似方法? - Alex Aparin
1
@АлександрЛысенко 看起来不是这样,但我也不明白为什么有人会通过反射创建元组类型。元组被设计用于在小范围(本地)内使用。因此,它们不应该离开方法体。其他任何情况都可能是代码异味的第一种表现形式。 - CSharpie
@Lasse V. Karlsen,我认为这个实现会引起你的兴趣)) https://referencesource.microsoft.com/System.Core/a.html#0788e95ecadc4631 - Alex Aparin

2

请注意,通用类型的名称形式为T`N,其中N是通用参数的数量。因此,所有Func委托都有一个系统化的名称,使我们可以轻松地获取类型:

Type create_type(Type[] types) {
    return Type.GetType($"System.Func`{types.Length}").MakeGenericType(types);
}

不能保证这种方法的效率,但如果您正在运行时构造这些类型,则可能并不是主要关注点。


鉴于存在Expression.GetFuncType,这个答案当然是低劣的,但出于某种教育目的,我将其保留。这在9个参数之外停止工作,因为具有超过9个参数的System.Func委托位于System.Core而不是mscorlib,因此需要一个程序集限定名称。修复很容易(检查并有条件地添加System.Core到名称中),但由于存在GetFuncType,因此不必要。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接