2012-11-06 21 views
18

Tôi muốn thực hiện một số thao tác trên chuỗi công nhân khi hiển thị thanh tiến trình cho người dùng. Tôi đã tạo một lớpCách sử dụng .NET Action để thực hiện một phương thức với số tham số không xác định?

public class ProgressBar 
{ 
    public void StartAsyncTask(Action action) 
    { 
     Task t = new Task(action); 
     t.start(); 
    } 
} 

tôi phát hiện ra rằng tôi có thể gửi bất kỳ phương pháp để các StartAsyncTask theo cách sau:

ProgressBar pb = new ProgressBar(); 
    pb.StartAsyncTask(() => DoSomething(15, "something")); 

    public void DoSomething(int i, string s) 
    { 
     //do something 
    } 

Trước hết, tôi dường như không thể hiểu những gì là và cách biểu thức lambda - () => - được dịch và cách đối tượng Action truyền một đại biểu với số lượng tham số không xác định.

Tôi muốn sử dụng BackgroundWorker với ProgressBar của mình nhưng trong trường hợp này tôi cần phải gọi hành động. Vì vậy, một cái gì đó như thế này:

void m_backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    Action action = e.Argument as Action; //same action here passed through EventArgs 
    //but already in a worker thread so no need for the Task object 

    //and now i need to somehow invoke the action object but i don't know what the parameters are. 

    action.Invoke(?); 
} 

Làm thế nào là nó có thể ở ví dụ đầu tiên để thực hiện thao tác mà không biết các thông số trong StartAsyncTask(Action action) phương pháp?

Tại sao tôi cần biết thông số khi gọi hành động trong trường hợp này?

Mọi thứ về cách/tại sao/khi nào sử dụng "Action" là không rõ ràng đối với tôi ngay cả khi tôi đọc tài liệu MSDN và một số chủ đề khác tại đây. Mọi thông tin về điều này sẽ giúp tôi.

+0

Bạn cần phải biết các thông số khi gọi nó .. khác (nếu nó có thể không để vượt qua các thông số) Hàm sẽ không có bất kỳ tham số nào được truyền vào nó .. do đó thực hiện lệnh 'parameter.Something' đầu tiên của bạn ném một' NullReferenceException'. –

Trả lời

47

Tôi nghĩ bạn đang suy nghĩ quá mức một chút. Vì vậy, chúng ta hãy bắt đầu từ đầu:

  1. Biểu thức lambda là một ký hiệu để tham chiếu thực hiện phương pháp. Ví dụ:

    x => x + 3 
    

    Ở mức cơ bản nhất, đây là đại diện cho một hàm mang theo 1 đầu vào, x, và sau đó trả về một giá trị bằng x + 3. Vì vậy, trong trường hợp của bạn, biểu thức của bạn:

    () => DoSomething(15, "Something") 
    

    Trình bày phương thức lấy 0 tham số và sau đó gọi phương thức DoSomething(15, "Something"). Trình biên dịch phía sau các cảnh biên dịch thành một đại diện Func hoặc Action cho bạn. Vì vậy, nó có hiệu lực:

    new Action(delegate() 
    { 
        DoSomething(15, "Something") 
    }); 
    

    Trình biên dịch viết lại biểu hiện đơn giản của tôi ở trên sẽ là:

    new Func<int, int>(delegate(int x) 
    { 
        return x + 3; 
    }); 
    
  2. Tiếp theo, nếu bạn muốn gọi một hành động sau, cú pháp để làm như vậy là khá đơn giản:

    Action someMethod = new Action(() => { Console.WriteLine("hello world"); })); 
    someMethod(); // Invokes the delegate 
    

    vì vậy, nếu bạn có một trao Action dụ, chỉ cần gọi nó với cú pháp () là tất cả các bạn cần, vì Action là một đại biểu có 0 tham số và không trả về gì cả.

    Một chức năng là tương tự dễ dàng:

    Func<int, int> previousGuy = x => x + 3; 
    var result = previousGuy(3); // result is 6 
    
  3. Cuối cùng, nếu bạn muốn vượt qua cùng một phương pháp để gọi, và bạn không có bối cảnh cho các thông số tại thời điểm đó, bạn có thể chỉ đơn giản là quấn của bạn gọi trong một hành động và gọi lại sau. Ví dụ:

    var myAction = new Action(() => 
        { 
          // Some Complex Logic 
          DoSomething(15, "Something"); 
          // More Complex Logic, etc 
        }); 
    
    InvokeLater(myAction); 
    
    public void InvokeLater(Action action) 
    { 
         action(); 
    } 
    

    Tất cả dữ liệu được chụp khi đóng phương pháp của bạn và do đó được lưu. Vì vậy, nếu bạn có thể quản lý để vượt qua một Action đến sự kiện của bạn với thuộc tính e.Argument, tất cả những gì bạn cần làm là gọi (e.Argument as Action)().

2

bạn không thể sử dụng DynamicInvoke() trên ủy nhiệm (phải mất params object[] args như là đối số)

action.DynamicInvoke(arg1, arg2, arg3); 
Các vấn đề liên quan