サーチ…


F#見積もりを使用した堅牢な反映

反射は有用だが壊れやすい。このことを考慮:

let mi  = typeof<System.String>.GetMethod "StartsWith"

この種のコードの問題は次のとおりです。

  1. String.StartsWithいくつかのオーバーロードがあるため、コードは機能しませんString.StartsWith
  2. 過負荷がない場合でも、ライブラリの後のバージョンではランタイムクラッシュを引き起こす過負荷が追加される可能性があります
  3. Rename methodsようなリファクタリングツールは、反映されています。

つまり、既知のコンパイル時にランタイムがクラッシュするということです。それは次善のようだ。

F#引用符を使用すると、上記のすべての問題を回避することができます。いくつかのヘルパー関数を定義します:

open FSharp.Quotations
open System.Reflection

let getConstructorInfo (e : Expr<'T>) : ConstructorInfo =
  match e with
  | Patterns.NewObject (ci, _) -> ci
  | _ -> failwithf "Expression has the wrong shape, expected NewObject (_, _) instead got: %A" e


let getMethodInfo (e : Expr<'T>) : MethodInfo =
  match e with
  | Patterns.Call (_, mi, _) -> mi
  | _ -> failwithf "Expression has the wrong shape, expected Call (_, _, _) instead got: %A" e

このような関数を使う:

printfn "%A" <| getMethodInfo <@ "".StartsWith "" @>
printfn "%A" <| getMethodInfo <@ List.singleton 1 @>
printfn "%A" <| getConstructorInfo <@ System.String [||] @>

これは印刷します:

Boolean StartsWith(System.String)
Void .ctor(Char[])
Microsoft.FSharp.Collections.FSharpList`1[System.Int32] Singleton[Int32](Int32)

<@ ... @>は、 F#内の式を実行する代わりに、式を表す式ツリーを生成することを意味します。 <@ "".StartsWith "" @>は次のような式ツリーを生成します: Call (Some (Value ("")), StartsWith, [Value ("")])この式ツリーは、 getMethodInfo期待するものと一致し、正しいメソッド情報を返します。

これにより、上記のすべての問題が解決されます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow