Strange reflection error on supposed type

I have some weird effects when trying to run f # code through reflection.
Given the following type

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

and this function

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

I can easily and correctly run the following code

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

However, I need to run this function on the sharp edges of my system boundaries, and the only way to do this is to return to using reflection.
Therefore, I created this function, which should perform a function similar to the above, and write this type and apply it.

 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 fv = let m = methi f m.Invoke(null, [|box v|]) apply fv :?> 't 

If I run it now, as shown below.

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

I get the following error

 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 

Who is trying to convert something to Box<obj, obj> and why?
Any help is appreciated

PS: Some clarifications ;-)
a) this is clearly a question about using reflection in the context of F #
b) Yes, I know that my real problem can be solved without thinking, and I already did it. This increases my code size by 40%. c) Yes, I know that thinking is a dog slowly. I am willing to trade speed (I do not need) for cleaner code.

+5
source share
2 answers

The signature of the convert function contains the explicit generic parameter 't , but not 'a . It splits the type inference for argument v .

Must be:

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

But explicit parameters are hard to use. I prefer to store conversion information in an expression:

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

Examples ( 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) 
+6
source

Who is trying to convert something into a box and why?

Since you are using Reflection, your MethodInfo reads general parameters as obj here

 Call (x, mi, y) -> mi 

Then you can do an upcast as below

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

Source: https://habr.com/ru/post/1260035/


All Articles