F#インタラクティブは、WinFormまたはWpfウィンドウのいずれかを実行し、そこで任意のコードを呼び出すことができるため、強力な開発ツールです。
これにより、「コードを試す前に試す」アプローチが可能になります。
非常に頻繁に私は「境界を破る」ことを明示的に望んでいます
- プライベート/保護されたメソッドを呼び出す
- プライベートフィールドとプロパティへのアクセス/変更
これを達成するための回避策はありますか?
F#インタラクティブは、WinFormまたはWpfウィンドウのいずれかを実行し、そこで任意のコードを呼び出すことができるため、強力な開発ツールです。
これにより、「コードを試す前に試す」アプローチが可能になります。
非常に頻繁に私は「境界を破る」ことを明示的に望んでいます
これを達成するための回避策はありますか?
FSI はこれに対して特別なサポートを提供していませんが、Reflection を使用して必要なことを行うことができます。
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 *)
public または private のフィールド、プロパティ、またはメソッドを解決するための粗いコードを次に示します。これが失敗する方法はたくさんあることに注意してください (特に、オーバーロードされたメソッドで使用しようとするとうまくいきません)。
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