2016-11-20 6 views
5

リフレクションでf#コードを実行しようとすると、私はいくつかの奇妙な効果があります。
は、私は鋭いエッジでこの関数を実行する必要があるしかし、私は簡単にかつ正確に次のコード推測された型での奇妙な反射エラー

let r01 = iToS (Box (1, 1)) 

を実行することができ、次のタイプ

type Box<'a, 'b> = Box of 'a * 'b 

と、この機能

//iToS :: Box<'a,'b> -> Box<string,'b> 
let iToS (Box (i, v)) = Box ((sprintf "%A" i), v) 

を考えますそれを行う唯一の方法は、リフレクションの使用法に戻すことです。
私は、上記のような関数と指定された型のレコードを取得し、それを適用するこの関数を作成しました。

let convert<'t> (f:Quotations.Expr) (v:'a) : 't = 
    let methi e = 
     let rec methi' e = 
      match e with 
       | Call (x, mi, y) -> mi 
       | Lambda (_, body) -> methi' body 
       | _ -> failwith <| sprintf "not a function %A" e 
     methi' e 

    let apply f v = 
     let m = methi f 
     m.Invoke(null, [|box v|]) 

    apply f v :?> 't 

これを今のところ以下のように実行するとします。

let r10 = (convert<Box<string, int>> <@ iToS @>) (Box (1, 1)) 

私はなぜBox<obj, obj>とに何かを変換しようとしている次のエラー

System.ArgumentException : Object of type 'Box`2[System.Int32,System.Int32]' cannot be converted to type 'Box`2[System.Object,System.Object]'. 
at System.RuntimeType.CheckValue (System.Object value, System.Reflection.Binder binder, System.Globalization.CultureInfo culture, System.Reflection.BindingFlags invokeAttr) [0x0007d] in <8cd55ece525b4760b63de40980e005aa>:0 
at System.Reflection.MonoMethod.ConvertValues (System.Reflection.Binder binder, System.Object[] args, System.Reflection.ParameterInfo[] pinfo, System.Globalization.CultureInfo culture, System.Reflection.BindingFlags invokeAttr) [0x0007f] in <8cd55ece525b4760b63de40980e005aa>:0 
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00014] in <8cd55ece525b4760b63de40980e005aa>:0 
at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <8cd55ece525b4760b63de40980e005aa>:0 
at convert[t] (Microsoft.FSharp.Quotations.FSharpExpr f, Box`2[a,b] v) [0x00006] in <5831a15618eafa12a745038356a13158>:0 
at test convert() [0x000e6] in <5831a15618eafa12a745038356a13158>:0 
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) 
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in <8cd55ece525b4760b63de40980e005aa>:0 

を取得しますか?
すべてのヘルプは

PS高く評価され:ええ、私は私の本当の問題は、反射せずに解決できる知っている)いくつかの明確化;-)
a)は、これは明示的にF#
Bのコンテキスト内で反射を使用してについての質問です私はすでにそうしています。私のコードサイズを40%も簡単に増やすことができます。
c)ええ、私は反射が犬遅いことを知っています。私はクリーナーコードの速度を交換する(私は必要ありません)喜んでです。

答えて

6

関数convertの署名には、明示的な汎用パラメータ'tが含まれていますが、'aではありません。引数vの型推論が中断されます。

は次のようになります。

let convert<'t, 'a> (f:Quotations.Expr) (v:'a) : 't 

しかし、明示的なパラメータが使用するのは困難です。私はむしろ表現に変換についての型情報を格納したい:

let convert (f:Quotations.Expr<'a -> 't>) (v:'a) : 't 

例(http://ideone.com/peLJAR):

let r10 = (convert <@ iToS @>) (Box (1, 1)) 
> val r10 : Box<string,int> = Box ("1",1) 

let r20 = (convert <@ iToS @>) (Box (1.0, 1.0)) 
> val r20 : Box<string,float> = Box ("1.0",1.0) 
+0

こんにちは以下、感謝のようなupcastを行うことができ、ここでobj

Call (x, mi, y) -> mi 

として汎用パラメータを読んでいます - それはうまくいきません:-( 'let convert(f:Quotations.Expr <'t -> 'a)(v:' a): 't'はコンパイルされません。(f:Quotations.Expr)(v: 'a):' t'は前と同じエラーになります。さらに、最大の問題は、私はそれが持っていないので、一般的なパラメータとして型を入れないことです(少なくともこの部分ではありません) – robkuz

+2

私は答えが間違った順序であると思います。 'let convert(f:Quotations.Expr <'a -> 't>)(v:' a): 't ='を試してみませんか? –

+0

ありがとう!私はこのタイプミスを修正します。 – gsomix

3

はなぜボックスとに何かを変換しようとしていますか?あなたはリフレクションを使用しているので

、あなたはMethodInfoそして、あなたが答えを

let r10 = (convert<Box<string, obj>> <@ iToS @>) (Box((upcast 1 : obj), (upcast 1 : obj)))