2012-11-06 44 views
18

我想在向用戶顯示進度條的同時在工作線程上執行一些操作。我創建了一個類如何使用.NET Action來執行一個參數數量未知的方法?

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

我發現我可以通過以下方式發送任何方法將StartAsyncTask

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

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

首先,我似乎無法理解什麼是以及lambda表達式如何翻譯?Action對象如何傳遞具有未知數量參數的委託。

我想使用BackgroundWorker與我的ProgressBar,但在這種情況下,我需要調用該操作。因此,像這樣:

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(?); 
} 

怎麼可能在第一個例子沒有StartAsyncTask(Action action)方法知道的參數來執行操作?

爲什麼在這種情況下調用動作時需要知道參數?

所有關於如何/爲什麼/何時使用「Action」對我來說都很不清楚,即使我在這裏閱讀MSDN文檔和一些其他主題。有關這方面的任何信息都會對我有所幫助。

+0

你打電話時,它需要知道的參數..否則,(如果有可能不通過參數)該函數不會有任何參數傳遞給它..因此,使你的第一個'parameter.Something'調用拋出'NullReferenceException'。 –

回答

47

我認爲你有點過度想象了。所以讓我們從頂端開始:

  1. lambda表達式是引用方法執行的符號。例如:

    x => x + 3 
    

    在最基本的級別,這是表示一個函數,它1個輸入,x,然後返回等於x + 3的值。因此,在你的情況,你的表達:

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

    表示取0參數,然後調用方法DoSomething(15, "Something")的方法。編譯器在後臺將其翻譯爲您的代表FuncAction。因此,它實際上是:

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

    我簡單表達的編譯器重寫上面會:

    new Func<int, int>(delegate(int x) 
    { 
        return x + 3; 
    }); 
    
  2. 接下來,如果你想在以後調用操作,這樣做的語法也是如此相當簡單:

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

    所以,如果你有一個給定的Action例如,簡單地用()語法調用它是你所需要的,因爲Action是一個採用0參數且不返回任何內容的委託。

    功能是同樣簡單:

    Func<int, int> previousGuy = x => x + 3; 
    var result = previousGuy(3); // result is 6 
    
  3. 最後,如果你想沿着調用方法傳遞,而不必在該點的參數情況下,你可以簡單地包裝你調用一個動作並稍後調用它。例如:

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

    所有的數據都會在您的方法的關閉中被捕獲並保存。因此,如果您可以設法將Action傳遞給e.Argument屬性的活動,則您只需致電(e.Argument as Action)()即可。

2

你能不能對委託使用DynamicInvoke()(它需要params object[] args作爲參數)

action.DynamicInvoke(arg1, arg2, arg3); 
相關問題