如何从FSharp中的反射调用Map.Add?

时间:2017-11-10 13:32:29

标签: dictionary reflection f#

鉴于FSI中的以下代码:

type Mapping = Map<int,string>

let mm = [ for i in Assembly.GetAssembly(typeof<Mapping>).ExportedTypes do yield i]|> List.find(fun m -> m.Name.Contains("MapModule"))
let mt = mm.GetMethod("Empty", BindingFlags.Static ||| BindingFlags.Public)
let mymap = mt.MakeGenericMethod([|typeof<string>; typeof<string>|]).Invoke(null, [||])

let addmethod = typeof<Mapping>.GetMethod("Add")

addmethod.Invoke(mymap, [|box(1);box("astring")|])

最后一行产生此错误:

  

System.Reflection.TargetException:Object与目标类型不匹配。      at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)      在System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj,BindingFlags invokeAttr,Binder binder,Object []参数,CultureInfo文化)      在System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,Binder binder,Object []参数,CultureInfo文化)      在System.Reflection.MethodBase.Invoke(Object obj,Object []参数)      at。$ FSI_0006.main @()   因错误而停止

即使您切换intstring参数,也会出现此错误。

有趣的是,以下代码有效:

type Mapping = Map<string,string>

let mm = [ for i in Assembly.GetAssembly(typeof<Mapping>).ExportedTypes do yield i]|> List.find(fun m -> m.Name.Contains("MapModule"))
let mt = mm.GetMethod("Empty", BindingFlags.Static ||| BindingFlags.Public)
let mymap = mt.MakeGenericMethod([|typeof<string>; typeof<string>|]).Invoke(null, [||])

let addmethod = typeof<Mapping>.GetMethod("Add")
addmethod.Invoke(mymap, [|box("a");box("b")|])

那么如何从反射中有效地调用Map.Add?

1 个答案:

答案 0 :(得分:2)

找到它。

这一行:

let mymap = mt.MakeGenericMethod([|typeof<string>; typeof<string>|]).Invoke(null, [||])

应该是:

let mymap = mt.MakeGenericMethod([|typeof<int>; typeof<string>|]).Invoke(null, [||])

类型不匹配实际上是真实的,因为&#34;空&#34;使用不正确的泛型类型调用方法。

所以这最终是正确的代码:

type Mapping = Map<int,string>

let mm = [ for i in Assembly.GetAssembly(typeof<Mapping>).ExportedTypes do yield i]|> List.find(fun m -> m.Name.Contains("MapModule"))
let mt = mm.GetMethod("Empty", BindingFlags.Static ||| BindingFlags.Public)
let am = mm.GetMethod("Add", BindingFlags.Static ||| BindingFlags.Public)
let mymap = mt.MakeGenericMethod([|typeof<int>; typeof<string>|]).Invoke(null, [||])
let addmethod = typeof<Mapping>.GetMethod("Add")

addmethod.Invoke(mymap, [|box(1);box("astring")|])