如何在F#中获取System.Func`3的指定CIL构造函数(ConstructorInfo)
获取F#中Func`3的指定构造函数及动态实现方案
这个问题我之前也踩过坑,主要是两个地方出错了——选了错误的类型,还有没指定正确的反射绑定标记,我给你一步步拆解解决:
一、固定类型(Func<int,int,int>)的正确做法
你之前用typeof<int * int * int>是错的,这是元组类型(Tuple<int,int,int>),而不是你要的Func<int,int,int>委托类型。另外,这个构造函数不是公共构造函数,默认的GetConstructor只会找公共成员,所以必须指定绑定标记才能找到它。
正确的F#代码如下:
open System open System.Reflection // 获取Func<int, int, int>的目标构造函数 let getFunc3Ctor () = // 正确的委托类型:Func<int, int, int> let funcType = typeof<Func<int, int, int>> // 必须包含Instance + Public + NonPublic,因为构造函数是非公共的 let bindingFlags = BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic // 构造函数参数:obj对应CIL的object,nativeint对应CIL的native int let ctorParams = [| typeof<obj>; typeof<nativeint> |] // 获取构造函数 funcType.GetConstructor(bindingFlags, null, ctorParams, null) // 测试调用 let ctor = getFunc3Ctor () printfn "构造信息:%A" ctor // 现在会返回有效的ConstructorInfo,不再是null
为什么之前的代码返回null?
- 类型错误:
int * int * int是元组,不是Func<int,int,int>委托,这两个完全是不同的类型。 - 绑定标记缺失:这个构造函数继承自
Delegate的protected构造函数,默认的GetConstructor只搜索公共构造函数,所以必须显式指定NonPublic标记才能找到它。
二、动态处理任意类型列表的方案
如果要替换成随机的System.Type列表,核心是动态构造对应的Func泛型委托类型,再用同样的反射逻辑获取构造函数。步骤如下:
- 根据类型列表的长度,找到对应的
Func泛型定义(比如3个类型对应Func3,5个类型对应Func5)。 - 用
MakeGenericType生成具体的委托类型。 - 用同样的绑定标记获取构造函数。
实现代码如下:
open System open System.Reflection /// 动态获取对应Func委托的目标构造函数 /// types列表:前N-1个是输入参数类型,最后一个是返回值类型(列表长度至少为1) let getDynamicFuncConstructor (types: Type list) = if types.Length < 1 then invalidArg "types" "类型列表至少需要包含一个元素(返回值类型)" // 获取对应的Func泛型定义,比如3个类型对应System.Func`3 let funcTypeName = $"System.Func`{types.Length}" let funcTypeDef = typeof<Delegate>.Assembly.GetType(funcTypeName) if isNull funcTypeDef then invalidArg "types" $"不支持长度为{types.Length}的类型列表(Func泛型最多支持17个类型参数)" // 生成具体的Func委托类型 let concreteFuncType = funcTypeDef.MakeGenericType(types.ToArray()) // 获取目标构造函数 let bindingFlags = BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic let ctorParams = [| typeof<obj>; typeof<nativeint> |] concreteFuncType.GetConstructor(bindingFlags, null, ctorParams, null) // 测试示例:获取Func<int, string, bool>的构造函数 let testTypes = [typeof<int>; typeof<string>; typeof<bool>] let dynamicCtor = getDynamicFuncConstructor testTypes printfn "动态构造信息:%A" dynamicCtor
注意事项
- Func泛型的类型参数最多支持17个(16个输入参数 + 1个返回值),所以类型列表的长度不能超过17。
- 这个构造函数主要用于.NET内部实现(比如编译器生成闭包),直接调用它需要传入正确的对象实例和方法指针,很容易出错,建议尽量避免直接使用。
内容的提问来源于stack exchange,提问作者AndreiXwe
相关产品推荐
相关产品推荐

