2011-07-26 2 views
5

Làm cách nào để tạo một thể hiện của Action<'T> bằng cách sử dụng sự phản chiếu? Dưới đây là những gì tôi có:Tạo một thể hiện của Hành động <'T> bằng cách sử dụng phản chiếu

let makeAction (typ:Type) (f:'T -> unit) = 
    let actionType = typedefof<Action<_>>.MakeGenericType(typ) 
    let converter = FSharpFunc.ToConverter(f) 
    Delegate.CreateDelegate(actionType, converter.Method) 

mà barfs với:

System.ArgumentException: Lỗi ràng buộc để nhắm mục tiêu phương pháp.
tại System.Delegate.CreateDelegate (Type type, phương pháp MethodInfo, Boolean throwOnBindFailure)

'T là một giao diện, mà typ cụ.

+0

Có lý do cụ thể nào bạn muốn thực hiện điều này bằng cách sử dụng sự phản chiếu không? Vì điều này có thể được thực hiện đơn giản như: 'let makeAction (f: 'a -> unit) = new Action <'a> (f)' – Ankur

+0

@Ankur: Vâng, bởi vì tôi không biết '' a' (trong ví dụ của bạn) tại thời gian biên dịch. – Daniel

+0

Không chắc chắn nếu tôi nhận được bạn một cách chính xác, nhưng ''a' ở đây là giống như'' T' trong mã của bạn, tức là một loại chung được giải quyết tùy thuộc vào giá trị 'f' được truyền. Bạn cần một loại hành động bao bọc hàm 'f' được truyền đi đúng không? – Ankur

Trả lời

3

Tôi nghĩ có hai vấn đề. Điều đầu tiên là bạn cần gọi CreateDelegate quá tải có ba đối số. Đối số bổ sung chỉ định cá thể mà phương thức cần được gọi.

Vấn đề thứ hai là Converter<'T, unit> thực sự biên dịch dưới dạng phương thức trả về Microsoft.FSharp.Core.Unit và không phải là phương thức trả về void. Tôi không chắc chắn nếu có một cách giải quyết dễ dàng hơn, nhưng bạn có thể xác định một wrapper có một phương pháp. Thành viên được biên soạn để trông giống như C#, vì vậy các loại đơn vị sẽ được biên dịch như void trong trường hợp đó:

open System 

type Wrapper<'T>(f:'T -> unit) = 
    member x.Invoke(a:'T) = f a 

let makeAction (typ:Type) (f:'T -> unit) = 
    let actionType = typedefof<Action<_>>.MakeGenericType(typ) 
    let wrapperType = typedefof<Wrapper<_>>.MakeGenericType(typ) 
    let wrapped = Wrapper<_>(f) 
    Delegate.CreateDelegate(actionType, wrapped, wrapped.GetType().GetMethod("Invoke")) 

makeAction (typeof<int>) (printfn "%d") 

EDIT - Đã làm một sự thay đổi nhỏ để làm cho nó thực sự làm việc trong kịch bản của bạn (với giao diện)

+0

Tuyệt vời. Cảm ơn! Tôi chỉ đang tạo 'Conversion' để lấy một' MethodInfo'. Tôi đã không chắc chắn làm thế nào khác để có được nó từ một chức năng F #. – Daniel

+0

@Daniel - Nếu bạn có hàm 'f', bạn cũng có thể sử dụng' f.GetType(). GetMethod ("Invoke") ', nhưng cung cấp cho bạn phương thức trả về' đơn vị', vì vậy nó sẽ không hoạt động trong trường hợp này. –

+0

Vâng, tôi đã cố gắng đầu tiên và thực hiện cùng một khám phá. – Daniel