2011-09-23 29 views

Trả lời

15

Cách nhanh nhất là cache một đại biểu đã nhập; nếu bạn biết chữ ký luôn là:

void PersonInstance.MethodName(string s); 

Sau đó, bạn có thể tạo ra một Action<Person,string> qua Delegate.CreateDelegate:

var action = (Action<Person,string>)Delegate.CreateDelegate(
    typeof(Action<Person,string>), method); 

này sau đó có thể được lưu trữ chống lại tên, và viện dẫn như:

action(personInstance, value); 

Lưu ý rằng bộ nhớ cache ở đây rất quan trọng; sự phản ánh để xác định phương pháp và chuẩn bị một đại biểu được đánh máy là không tầm thường.

Sẽ khó hơn nếu chữ ký không thể đoán trước, vì DynamicInvoke tương đối chậm. Cách cách nhanh nhất là sử dụng DynamicMethod và ILGenerator để viết một phương thức shim (trên bay) lấy đối tượng [] cho các tham số và bỏ gói và phôi nó khớp với chữ ký - sau đó bạn có thể lưu Action<object, object[]> hoặc Func<object,object[],object>. Đó là, tuy nhiên, một chủ đề nâng cao. Tôi có thể cung cấp một ví dụ nếu thực sự cần thiết. Về cơ bản bằng văn bản (khi chạy):

void DummyMethod(object target, object[] args) { 
    ((Person)target).MethodName((int)args[0],(string)args[1]); 
} 

Dưới đây là một ví dụ về làm điều đó (lưu ý: nó không xử lý ref/out args vào lúc này, và có thể là một vài tình huống khác - và tôi đã rời khỏi " bộ nhớ cache "bên của những thứ như một bài tập cho người đọc):

using System; 
using System.Reflection; 
using System.Reflection.Emit; 

class Program 
{ 
    static void Main() 
    { 
     var method = typeof(Foo).GetMethod("Bar"); 
     var func = Wrap(method); 
     object[] args = { 123, "abc"}; 
     var foo = new Foo(); 
     object result = func(foo, args); 
    } 

    static Func<object, object[], object> Wrap(MethodInfo method) 
    { 
     var dm = new DynamicMethod(method.Name, typeof(object), new Type[] { 
      typeof(object), typeof(object[]) 
     }, method.DeclaringType, true); 
     var il = dm.GetILGenerator(); 

     if (!method.IsStatic) 
     { 
      il.Emit(OpCodes.Ldarg_0); 
      il.Emit(OpCodes.Unbox_Any, method.DeclaringType); 
     } 
     var parameters = method.GetParameters(); 
     for (int i = 0; i < parameters.Length; i++) 
     { 
      il.Emit(OpCodes.Ldarg_1); 
      il.Emit(OpCodes.Ldc_I4, i); 
      il.Emit(OpCodes.Ldelem_Ref); 
      il.Emit(OpCodes.Unbox_Any, parameters[i].ParameterType); 
     } 
     il.EmitCall(method.IsStatic || method.DeclaringType.IsValueType ? 
      OpCodes.Call : OpCodes.Callvirt, method, null); 
     if (method.ReturnType == null || method.ReturnType == typeof(void)) 
     { 
      il.Emit(OpCodes.Ldnull); 
     } 
     else if (method.ReturnType.IsValueType) 
     { 
      il.Emit(OpCodes.Box, method.ReturnType); 
     } 
     il.Emit(OpCodes.Ret); 
     return (Func<object, object[], object>)dm.CreateDelegate(typeof(Func<object, object[], object>)); 
    } 
} 

public class Foo 
{ 
    public string Bar(int x, string y) 
    { 
     return x + y; 
    } 
} 
+0

Tôi muốn xem ví dụ về cách sử dụng DynamicMethod và ILGenerator (nếu không quá nhiều rắc rối). – StriplingWarrior

+2

@StriplingWarrior không phải là một vấn đề, không - tôi, tuy nhiên, hiện nay trên iPod, mà không cho vay chính nó tốt để viết mã IL-emit. Tôi có thể thêm một ví dụ trong một vài giờ khi tôi đang ở một máy tính? –

+0

+1 tốt đẹp. Tôi đã phải thử nó và nó hoạt động !. – kenny

Các vấn đề liên quan