2016-11-20 14 views
5

Tôi có một số hiệu ứng lạ khi cố chạy mã f # qua phản xạ.
Với loại sau đâyLỗi phản chiếu lạ trên kiểu được suy ra

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

và chức năng này

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

tôi có thể dễ dàng và chính xác chạy đoạn mã sau

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

Tuy nhiên tôi cần phải chạy chức năng này ở các cạnh sắc nét các ranh giới hệ thống của tôi và cách duy nhất để làm như vậy là giảm sử dụng phản chiếu.
Vì vậy, tôi đã tạo ra chức năng này nên có một chức năng như trên và một bản ghi của các loại nhất định và áp dụng nó.

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 

Nếu bây giờ tôi chạy ứng dụng này như dưới đây.

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

tôi nhận được lỗi sau

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 

Ai đang cố gắng để chuyển đổi một cái gì đó vào một Box<obj, obj> và tại sao?
Any help is appreciated

PS: Một số làm rõ ;-)
a) đây là một cách rõ ràng một câu hỏi về việc sử dụng phản ánh trong bối cảnh của F #
b) yeah, tôi biết vấn đề thực sự của tôi có thể được giải quyết mà không cần suy nghĩ và tôi đã làm như vậy rồi. Nó làm tăng kích thước mã của tôi một cách dễ dàng 40%.
c) vâng, tôi biết sự phản chiếu là con chó chậm. Tôi sẵn sàng để giao dịch tốc độ (tôi không cần) cho mã sạch hơn.

Trả lời

6

Chữ ký của hàm convert chứa thông số chung chung rõ ràng 't, nhưng không phải là 'a. Nó phá vỡ suy luận kiểu cho đối số v.

nên là:

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

Nhưng rõ ràng các thông số rất khó để sử dụng. Tôi muốn lưu trữ một loại thông tin về chuyển đổi trong biểu thức:

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

Ví dụ (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

Hi, cảm ơn cho câu trả lời - alas nó không hoạt động :-( 'cho phép chuyển đổi (f: Báo giá.Expr <'t -> 'a>) (v:' a): 't' sẽ không biên dịch trong khi' để chuyển đổi <'t, 'a> (f: Báo giá.Expr) (v: 'a):' t' bị lỗi giống như trước. Ngoài ra vấn đề lớn nhất là tôi không thể đặt các loại như các tham số chung như tôi không có sau đó (ít nhất là không phải ở phần này của programm) – robkuz

+2

Tôi nghĩ rằng các loại là một thứ tự sai trong câu trả lời. Bạn có thể thử 'let convert (f: Quotations.Expr <'a -> 't>) (v:' a): 't ='? –

+0

Cảm ơn! Tôi sẽ sửa lỗi này. – gsomix

3

Ai đang cố gắng để chuyển đổi một cái gì đó vào một hộp và tại sao?

Vì bạn đang sử dụng Reflection, bạn MethodInfo đang đọc các thông số chung chung như obj đây

Call (x, mi, y) -> mi 

Sau đó, bạn có thể làm một upcast như dưới đây

let r10 = (convert<Box<string, obj>> <@ iToS @>) (Box((upcast 1 : obj), (upcast 1 : obj))) 
Các vấn đề liên quan