У меня есть некоторые странные эффекты при попытке запустить код f # через отражение.
Учитывая следующий типСтранная ошибка отражения на выводимом типе
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 r01 = iToS (Box (1, 1))
Однако мне нужно запустить эту функцию на острых кромках моих системных границ, и единственный способ сделать это - вернуться к использованию рефлексии.
Итак, я создал эту функцию, которая должна выполнять функцию, подобную приведенной выше, и запись данного типа и применять ее.
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))
Я получаю следующую ошибку
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
Кто пытается превратить что-то в Box<obj, obj>
и почему?
Любая помощь приветствуется
PS: Некоторые пояснения ;-)
а) это явно вопрос об использовании отражения в контексте F #
б) да, я знаю, что моя реальная проблема может быть решена без отражения и я уже сделал это. Это увеличивает мой размер кода на 40%.
c) Да, я знаю, что отражение - собака медленно. Я готов торговать скоростью (я не нуждаюсь) для более чистого кода.
Привет, спасибо за ответ - увы, он не работает :-( 'let convert (f: Quotations.Expr <'t -> 'a>) (v:' a): 't' даже не компилируется, тогда как' let convert <'t, 'a> (f: Quotations.Expr) (v: 'a):' t' получает ту же ошибку, что и раньше. Кроме того, самая большая проблема заключается в том, что я не могу поместить типы в качестве общих параметров, которые у меня тогда нет (по крайней мере, не в этой части программы) – robkuz
Я думаю, что типы не соответствуют порядку в ответе. Не могли бы вы попробовать 'let convert (f: Quotations.Expr <'a -> 't>) (v:' a): 't ='? –
Спасибо! Я исправлю эту опечатку. – gsomix