2015-12-09 44 views
1

我想通過的方法返回void並接受a參數int。我怎麼做?使用操作和任務

有人可以告訴我非lambda和lambda版本嗎?

 private void LongTask(int s) 
     { 

      Thread.Sleep(s* 1000); 
     } 


     public void Run() 
     { 
      Task q = Task.Run(Action<int>(LongTask)); 

     } 
+0

lambda會導致由編譯器爲您創建一個閉包。如果必須的話,您可以自己創建閉包。基本上,創建一個類,它將'int s'存儲爲一個字段/屬性,然後調用作用於'int s'字段的'void NameYourMethod()',並在將它包裝到'Action'中後調用傳遞給'Task.Run' ......但是爲什麼你不想使用lambdas呢? –

+0

這個問題與多線程有什麼關係? –

回答

1

在您的示例中,您沒有顯示傳遞給該方法的值。這使得有點難以確切地知道你甚至在問什麼。但我認爲您要求說明如何調用您的方法LongTask(),傳遞適當的值作爲Task.Run()操作,並使用lambda語法和非lambda語法來提供此說明。

說明:很少有這實際上是特定於Task.Run()。無論何時,您都在處理將委託傳遞給委託需要用與您調用的方法中使用的簽名不同的方法表示方法的方法。這裏涉及的Task.Run()幾乎是附帶的。

無論如何&hellip;

實際上,因爲lambda表達式(在此用法)編譯爲匿名方法,真的有三種選擇:

「老派」匿名方法:

public void Run() 
{ 
    int someValue = 17; 

    Task q = Task.Run(delegate { LongTask(someValue); }); 
} 

以上使編譯器創建匿名方法(delegate() { LongTask(someValue); }),並生成代碼以創建委託實例以傳遞給Task.Run()方法。委託的類型是根據用法推斷出來的(即基於與匿名方法聲明匹配的一個方法重載)。

LAMBDA匿名方法:

public void Run() 
{ 
    int someValue = 17; 

    Task q = Task.Run(() => LongTask(someValue)); 
} 

上面就像前面的例子,不同的是使用標稱更簡潔lambda語法來聲明匿名方法。我說「名義上」,因爲在這個特殊情況下,它並不是那麼短。但還有其他一些情況,lambda語法更方便;通常,當匿名方法返回一個值時,由於使用lambda語法,暗示了return語句。

明確:

class A 
{ 
    private readonly int _value; 
    private readonly Action<int> _action; 

    public A(int value, Action<int> action) 
    { 
     _value = value; 
     _action = action; 
    } 

    public void M() { _action(_value); } 
} 

public void Run() 
{ 
    int someValue = 17; 

    Task q = Task.Run((Action)(new A(someValue, LongTask).M)); 
} 

以上依賴於一個明確寫入類達到同樣的目的,因爲編譯器生成的類匿名方法的選擇導致根據具體情況,編譯器生成的類可能在實現上有很大的不同。但是行爲本質上是相同的:創建一個類的實例,在該實例中存儲所需的值,並在該類中包含適當簽名的方法,其中該方法的主體是要執行的代碼。 (另外:在這種情況下,爲了簡明起見,我已經展示了一個實際上需要委託實例而不是硬編碼目標對象和方法調用的實現。這實際上是比編譯器實際產生的更可重用的實現,主要是因爲編譯器必須處理更復雜的場景,這是一種優化,僅在非常狹窄的情況下有用,即只有一種方法被調用。編譯器也將存儲this並且將匿名方法的主體拷貝到所生成的方法,使用存儲的this引用以及根據需要的任何其他捕獲的變量,例如,調用LongTask()方法。)

在可變_value以上是readonly,但在匿名方法,他們將通常爲匿名方法的上下文中拍攝的可變變量。爲了更好地模擬如何匿名方法通常會工作,你想要更多的東西是這樣的:

class A 
{ 
    public int value; 
    private readonly Action<int> _action; 

    public A(int value, Action<int> action) 
    { 
     this.value = value; 
     _action = action; 
    } 

    public void M() { _action(value); } 
} 

public void Run() 
{ 
    A a = new A(17, LongTask); 

    Task q = Task.Run((Action)a.M); 

    a.value = 19; 
} 

注意,在上述情況,value是公共領域。代碼實際上在調用Task.Run()後修改了變量。這類似於在匿名方法示例中更改someValue的值(同樣,在調用Task.Run()後),並具有相同的風險:如果在任務可以執行方法調用之前執行Task.Run()方法之後的賦值,那麼您會得到一個傳遞給方法的值不同於任務可以先執行該方法的值。

道德:時刻關注您捕獲的變量,並確保他們擁有您期望他們擁有的生命和價值。


順便說,需要強制轉換爲所期望的委託類型Action在這最後的兩個例子中,因爲否則Task.Run()過載來選擇是不明確的編譯器,Task.Run(Action)Task.Run(Func<Task>)之間。短版本:嘗試從方法組轉換爲委託類型並將其與特定的過載進行匹配時,會忽略委託簽名的返回類型。對於更長的版本,請參閱Compiler Ambiguous invocation error - anonymous method and method group with Func<> or Action