2012-08-26 22 views
8

Tôi muốn để có thể thực hiện tương đương với sau khi chạy:Làm cách nào để tôi có thể tạo động một hành động <T> khi chạy?

var action = new Action<ANYTHING AT RUNTIME>(obj => Console.WriteLine("Called = " + obj)); 

Tôi biết tôi cần phải nhận được đúng loại cho các hành động, nhưng không chắc chắn làm thế nào để có được chút thức sử dụng Delegate.Create . Type thể hiện T trong định nghĩa Hành động.

var actionType = typeof(Action<>).MakeGenericType(Type); 
var constructor = actionType.GetConstructors()[0]; 
var @delegate = Delegate.CreateDelegate(actionType, <WHAT GOES HERE>); 

điểm mọi người dường như bị mất là tôi đang cố gắng để tạo ra một thể hiện của hành động đó T không thể được xác định tĩnh bởi vì nó đang được sử dụng từ một lớp học có nguồn gốc từ Thuộc tính - điều này có nghĩa T có thể là bất cứ điều gì và nó không thể được định nghĩa như một định nghĩa chung

Cheers

+0

Phần nào của 'action = new Action (obj => Console.WriteLine (" Called = "+ obj));' bạn có muốn tạo động không? – Mark

+0

Tôi muốn tạo \ khởi tạo tham số 'action' – AwkwardCoder

+0

Tôi đang bối rối. Không có _parameter_ gọi là 'action'. Bạn muốn đạt được những gì? – Mark

Trả lời

-1

Câu trả lời ngắn gọn là để tạo ra một đại biểu MyActionDelegate và sau đó sử dụng:

delegate void MyActionDelegate(T arg); 
Delegate @delegate = new MyActionDelegate((a) => Console.WriteLine(a)); 

Dưới đây là một ví dụ làm việc sử dụng một lớp chung:

public class MyClass<T> 
{ 
    public delegate void ActionDelegate(T arg); 

    public void RunGenericAction(T arg) 
    { 
     var actionType = typeof(Action<>).MakeGenericType(typeof(T)); 
     var constructor = actionType.GetConstructors()[0]; 
     Delegate @delegate = new ActionDelegate((a) => { Console.WriteLine(arg); }); 
     var inst = (Action<T>)constructor.Invoke(new object[] { 
      @delegate.Target, 
      @delegate.Method.MethodHandle.GetFunctionPointer() 
     }); 
     inst(arg); 
    } 
} 

Sử dụng nó như thế này, mà kết quả đầu ra 123 ra cửa sổ Console:

var c = new MyClass<int>(); 
c.RunGenericAction(123); 

Bạn sẽ nhận thấy tôi đang đi qua hai tham số để Constructor.Invoke; đó là bởi vì nó chỉ ra rằng một đối số đại biểu thực sự biên dịch thành hai đối số: đối tượng đích của hàm và một con trỏ trỏ tới hàm. Tôi không thể lấy tín dụng cho những bước chân ưa thích ở đó; thông tin "đã mượn" từ this excellent answer on how to pass a delegate argument using reflection.

-1

Sử dụng mã sau để tạo đại biểu, bị ràng buộc trễ trong thông số loại. Xem thêm How to: Examine and Instantiate Generic Types with Reflection.

abstract class ActionHelper { 

    protected abstract Delegate CreateActionImpl(); 

    // A subclass with a static type parameter 
    private class ActionHelper<T> : ActionHelper { 
     protected override Delegate CreateActionImpl() { 
      // create an Action<T> and downcast 
      return new Action<T>(obj => Console.WriteLine("Called = " + (object)obj)); 
     } 
    } 

    public static Delegate CreateAction(Type type) { 
     // create the type-specific type of the helper 
     var helperType = typeof(ActionHelper<>).MakeGenericType(type); 
     // create an instance of the helper 
     // and upcast to base class 
     var helper = (ActionHelper)Activator.CreateInstance(helperType); 
     // call base method 
     return helper.CreateActionImpl(); 
    } 
} 

// Usage 
// Note: The "var" is always "Delegate" 
var @delegate = ActionHelper.CreateAction(anyTypeAtRuntime); 

Điều đó nói rằng, tôi không khuyên bạn nên sử dụng phương pháp này. Thay vào đó, sử dụng

Action<object> action = obj => Console.WriteLine("Called = " + obj); 

Nó cung cấp

  • Các chức năng tương tự.

    Mã ban đầu của bạn "Called = " + obj" gọi .ToString() trên tham số. Vì vậy, hiện ở trên.

  • Không có sự khác biệt về hiệu suất.

    Nếu tham số obj là loại giá trị, cả hai biến thể đều thực hiện thao tác quyền anh. Việc đấm bốc trong lần đầu tiên không rõ ràng, nhưng "Called = " + obj" các loại giá trị hộp.

  • Ngắn hơn và ít xảy ra lỗi hơn.

+0

"Không có sự khác biệt về hiệu suất" bạn chưa cung cấp bất kỳ mã nào thực sự tạo một đại biểu. Bạn thuận tiện cung cấp một lớp trừu tượng với một phương thức trừu tượng 'CreateActionImpl' nhưng không cung cấp một triển khai thực hiện - phương thức duy nhất sẽ thực sự tạo động tác động. –

+0

@Peter Tôi đã giải thích các tác động về hiệu suất trong đoạn sau tuyên bố. Ngoài ra, OP muốn _just kiểu parameter_ của đại biểu bị ràng buộc trễ. Mà mã không có Reflection.Emit. – Mark

0

Bạn có thể sử dụng đoạn mã sau, nó hoạt động nếu loại có thể được đúc đến một đối tượng:

Action<object> func = o => Console.WriteLine("Called = " + o.GetType().Name); 
var actionType = typeof(Action<>).MakeGenericType(type); 
var constructor = actionType.GetConstructors()[0]; 
var @delegate = Delegate.CreateDelegate(actionType, func.Method); 

Tuy nhiên nếu loại là enum hoặc kiểu giá trị khác, nó sẽ không làm việc.

1

Nếu bạn biết thao tác cần thực hiện là gì và cách thực hiện thao tác bất kể loại (như trong ví dụ của bạn) tại sao không chỉ thực hiện phương pháp chung để thực hiện thao tác và tạo đại biểu theo cách đó?

class Program 
{ 
    public static void Perform<T>(T value) 
    { 
     Console.WriteLine("Called = " + value); 
    } 

    public static Delegate CreateAction(Type type) 
    { 
     var methodInfo = typeof (Program).GetMethod("Perform").MakeGenericMethod(type); 
     var actionT = typeof (Action<>).MakeGenericType(type); 
     return Delegate.CreateDelegate(actionT, methodInfo); 
    } 

    static void Main(string[] args) 
    { 
     CreateAction(typeof (int)).DynamicInvoke(5); 
     Console.ReadLine(); 
    } 
} 
Các vấn đề liên quan