F# インタラクティブを使用してプライベート フィールド/メソッド/プロパティにアクセスする方法

StackOverflow https://stackoverflow.com/questions/1666767

質問

F# interactive は、WinForm または Wpf ウィンドウのいずれかを実行できるため、強力な開発ツールです。 そして そこで任意のコードを呼び出します。

これにより、「コードを実行する前に試してみる」アプローチが可能になります。

非常に多くの場合、私は明示的に「境界を打ち破る」ことを望みます。

  • プライベート/保護されたメソッドを呼び出す
  • プライベートフィールドとプロパティへのアクセス/変更

これを達成するための回避策はありますか?

役に立ちましたか?

解決

FSIこのため、特定のサポートを提供していませんが、あなたが欲しいものを行うためにリフレクションを使用することができます。

open System.Reflection
let field = typeof<MyType>.GetField("fieldName", BindingFlags.NonPublic ||| BindingFlags.Instance)
field.SetValue(myInstance, newVal)

あなたはさらに行くと、これをさらに容易にするためにメソッドや演算子を定義することができます。たとえば、あなたがプライベートフィールドに割り当てるF#の動的な代入演算子を設定することができます:

let (?<-) o s v = 
  let field = (o.GetType()).GetField(s, BindingFlags.NonPublic ||| BindingFlags.Instance)
  field.SetValue(o,v)

myInstance?fieldName <- newVal (* Note: no quotes around fieldName here *)

ここでは、パブリックまたはプライベートフィールド、プロパティ、またはメソッドを解決するためにいくつかの粗コードです。これが失敗している方法の多くは、(特に、オーバーロードされたメソッドでそれを使用しようとすると、動作しません)があることに注意します。

open System
open System.Reflection
open Microsoft.FSharp.Reflection

type DynamicHelper =  
  static member MkMethod<'t,'u> (mi:MethodInfo) o : 't -> 'u=
    let typ = typeof<'t>
    fun t -> 
      let args = 
        if (typ = typeof<unit>) then [||]
        else
          if not (FSharpType.IsTuple typ) then [| box t |]
          else
            FSharpValue.GetTupleFields t
      mi.Invoke(o, args) :?> 'u

let (?) (o:'a) s : 'b =
  let ty = o.GetType()
  let field = ty.GetField(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
  if field <> null then field.GetValue(o) :?> 'b
  else
    let prop = ty.GetProperty(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
    if prop <> null then prop.GetValue(o, null) :?> 'b
    else
      let meth = ty.GetMethod(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
      let d,r = FSharpType.GetFunctionElements(typeof<'b>)
      typeof<DynamicHelper>.GetMethod("MkMethod").MakeGenericMethod([|d;r|]).Invoke(null, [| box meth; box o |]) :?> 'b

これを使用すると、動的などのメソッドとプロパティを呼び出すことができます:

let (t:System.Type) = "test"?GetType()?BaseType
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top