如何通过反射将F#函数转换为System.Delegate?
将F#函数转换为委托的正确方法
问题背景
有一个基础F#函数:
let double x = x * 2
显式使用Func<_,_>构造函数可以成功转换为委托:
let doubleFuncExplicit = Func<int, int>(double)
但尝试用Activator.CreateInstance反射创建时抛出MissingMethodException:
// 推导Func<int, int>类型 let genericType = typeof<Func<obj, obj>>.GetGenericTypeDefinition() let specificTypeDef = genericType.MakeGenericType([| typeof<int>; typeof<int> |]) // 实例化 let doubleFuncReflected = Activator.CreateInstance(specificTypeDef, [| double |])
异常信息:
System.MissingMethodException: Constructor on type 'System.Func`2[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]' not found. at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture) at System.Activator.CreateInstance(Type type, Object[] args) at <StartupCode$FSI_0007>.$FSI_0007.main@() in C:\dev\2023\MoneyClock2023\src\MoneyClock\MoneyClock.Tests\Scratch.fsx:line 16 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
问题原因
你的思路存在错误:委托类型(如Func<,>)不能通过Activator.CreateInstance直接实例化。
- 显式构造成功是因为F#编译器做了隐式转换:自动将F#原生函数(
FSharpFunc<int,int>类型)转换为对应的Func<int,int>委托,构造函数实际接收的是转换后的委托实例,而非原始F#函数对象。 - 反射调用时没有这个隐式转换,直接传递F#函数对象给
Activator.CreateInstance,找不到匹配的构造器,因此报错。
正确的转换方法
1. 显式构造(已知类型时)
这是你已经掌握的方法,F#编译器会自动处理类型转换:
let doubleFunc = Func<int, int>(double)
2. 使用LanguagePrimitives.FuncConvert显式转换
如果需要更明确的转换逻辑,可以用F#核心库的转换工具:
open FSharp.Core.LanguagePrimitives let doubleFunc = FuncConvert.ToFunc(double)
3. 反射方式(未知类型时)
当需要动态创建委托时,应该使用Delegate.CreateDelegate方法,而非Activator.CreateInstance。步骤如下:
// 1. 获取目标委托类型 let genericType = typeof<Func<obj, obj>>.GetGenericTypeDefinition() let specificType = genericType.MakeGenericType([| typeof<int>; typeof<int> |]) // 2. 获取F#函数的Invoke方法(FSharpFunc的Invoke方法就是函数执行入口) let fsharpFuncType = double.GetType() let invokeMethod = fsharpFuncType.GetMethod("Invoke") // 3. 创建委托实例 let doubleFuncReflected = Delegate.CreateDelegate(specificType, double, invokeMethod) :?> Func<int, int>
这段代码通过绑定F#函数的Invoke方法到目标委托类型,实现了反射下的类型转换。
内容的提问来源于stack exchange,提问作者Overlord Zurg
相关产品推荐
相关产品推荐

