简体   繁体   English

如何将System.Reflection.MemberInfo值转换为它表示的F#值?

[英]How can I convert a System.Reflection.MemberInfo value into the F# value it represents?

I'm trying to load and execute F# code at runtime. 我正在尝试在运行时加载和执行F#代码。 The FSharp.Compiler.Service assembly produces System.Reflection.MemberInfo values for each value (or function) definition in a program. FSharp.Compiler.Service程序集为程序中的每个值(或函数)定义生成System.Reflection.MemberInfo值。

I'm roughly trying to implement the following: 我正在粗略地尝试实现以下内容:

cast<'a> : System.Reflection.MemberInfo -> 'a

Which succeeds if the MemberInfo value represents a value of type 'a (and returns that value), or fails otherwise. 如果MemberInfo值表示类型'a的值(并返回该值),则成功,否则,失败。

First, your function will need to have an optional result - to indicate that it might not always succeed. 首先,您的函数需要有一个可选的结果-表示它不一定总是成功。

Then, members could be (a) nested types, (b) properties, (c) fields, and (d) methods. 然后,成员可以是(a)嵌套类型,(b)属性,(c)字段和(d)方法。 I'm guessing you're only interested in the latter three. 我猜您只对后三个感兴趣。

You will need to handle these three cases separately, because they are actually different things, not three kinds of the same thing. 您将需要分别处理这三种情况,因为它们实际上是不同的事物,而不是三种相同的事物。 For fields and properties, you can use FieldInfo.GetValue and PropertyInfo.GetValue respectively to obtain the value. 对于字段和属性,可以分别使用FieldInfo.GetValuePropertyInfo.GetValue来获取值。 For methods, you can use MethodInfo.Invoke to call it and return the result. 对于方法,可以使用MethodInfo.Invoke进行调用并返回结果。

Roughly: 大致:

let getValue<'a> (o: obj) (m: MemberInfo): 'a option =
  match m with
  | :? FieldInfo as f when f.FieldType = typeof<'a> -> 
    Some( f.GetValue o :?> 'a )
  | :? PropertyInfo as p when p.PropertyType = typeof<'a> && p.GetIndexParameters().Length = 0 -> 
    Some( p.GetValue( o, [||] ) :?> 'a )
  | _ -> None

let getFunc<'a, 'b> (o: obj) (m: MemberInfo): ('a -> 'b) option =
  match m with
  // F# compiler may compile some functions as properties of type FSharpFunc<_>, so need to cover that
  | :? FieldInfo -> getValue<'a -> 'b> o m
  | :? PropertyInfo -> getValue<'a -> 'b> o m

  // If it's a real method of the right type, create a closure to call it
  | :? MethodInfo as mt 
    when mt.ReturnType = typeof<'b> && 
         mt.GetParameters().Length = 1 &&
         mt.GetParameters().[0].ParameterType = typeof<'a> -> 
    Some <| fun (a: 'a) -> mt.Invoke( o, [| a :> obj |] ) :?> 'b

  // Otherwise, can't produce result
  | _ -> None

However, these dynamic invocations would be very slow. 但是,这些动态调用将非常缓慢。 From your question, I assume you're trying to do something like a REPL, for which this would be fine, but if you're looking at using this many times, repeatedly, a better way may be to create and compile LINQ Expressions using Expression.MakeMemberAccess for fields/properties and Expression.Call for methods. 根据您的问题,我假设您正在尝试做类似REPL的事情,这会很好,但是如果您打算多次使用它,那么更好的方法可能是使用以下方法创建和编译LINQ表达式: Expression.MakeMemberAccess用于字段/属性, Expression.Call用于方法。 Don't forget to cache the compiled delegates though, otherwise it would be even slower :-) 不过不要忘了缓存已编译的委托,否则它会更慢:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM