2012-10-21 116 views
27
public class test 
{ 
    public async Task Go() 
    { 
     await PrintAnswerToLife(); 
     Console.WriteLine("done"); 
    } 

    public async Task PrintAnswerToLife() 
    { 
     int answer = await GetAnswerToLife(); 
     Console.WriteLine(answer); 
    } 

    public async Task<int> GetAnswerToLife() 
    { 
     await Task.Delay(5000); 
     int answer = 21 * 2; 
     return answer; 
    } 
} 

如果我想在main()方法中調用Go,我該怎麼做? 我正在嘗試c#新功能,我知道我可以將異步方法掛接到事件,並通過觸發該事件,可以調用異步方法。如何在例如Main()中調用異步Go方法?

但是如果我想直接用main方法調用它呢?我怎樣才能做到這一點?

我不喜歡的東西

class Program 
{ 
    static void Main(string[] args) 
    { 
     test t = new test(); 
     t.Go().GetAwaiter().OnCompleted(() => 
     { 
      Console.WriteLine("finished"); 
     }); 
     Console.ReadKey(); 
    } 


} 

,但似乎這是一個死鎖和沒有打印在屏幕上。

+0

似乎我發現這個問題,COS GetAwaiter()OnCompleted()將返回主函數立即,所以當調用Console.Readkey()時,主線程被阻塞,因此從任務返回的輸出消息不能被打印到屏幕上,因爲它正在等待主線程解除阻塞。如果我用while替換Console.readkey()while(true) Thread.Sleep(1000); }它工作正常。 – Larry

+0

我無法重現您的死鎖問題,但是,如果有人在意..使用'Go()。ConfigureAwait(false).GetAwaiter()'在異步方法中使用新的上下文。 – arviman

回答

39

Main你方法可以簡化爲:

static void Main(string[] args) 
{ 
    test t = new test(); 
    t.Go().Wait(); 
    Console.WriteLine("finished"); 
    Console.ReadKey(); 
} 

這是async關鍵字(和相關的功能性)的美的一部分:回調的使用和混亂的性質大大降低或消除。

16

而是等待,你最好使用 new test().Go().GetAwaiter().GetResult() ,因爲這將避免異常被包裹成AggregateExceptions,所以你可以圍繞你的圍棋()與嘗試catch(異常前)塊如常法。

+0

IMO最佳答案你仍然可以返回強類型等。 –

4

只要您從返回的任務訪問結果對象,就根本不需要使用GetAwaiter(只有在您訪問結果的情況下)。

static async Task<String> sayHelloAsync(){ 

     await Task.Delay(1000); 
     return "hello world"; 

} 

static void main(string[] args){ 

     var data = sayHelloAsync(); 
     //implicitly waits for the result and makes synchronous call. 
     //no need for Console.ReadKey() 
     Console.Write(data.Result); 
     //synchronous call .. same as previous one 
     Console.Write(sayHelloAsync().GetAwaiter().GetResult()); 

} 

,如果你想等待要完成的任務,做一些進一步的處理:

sayHelloAsyn().GetAwaiter().OnCompleted(() => { 
    Console.Write("done"); 
}); 
Console.ReadLine(); 

如果你有興趣正從sayHelloAsync結果,並在其上做進一步的處理:

sayHelloAsync().ContinueWith(prev => { 
    //prev.Result should have "hello world" 
    Console.Write("done do further processing here .. here is the result from sayHelloAsync" + prev.Result); 
}); 
Console.ReadLine(); 

最後一個簡單的方法來等待功能:

static void main(string[] args){ 
    sayHelloAsync().Wait(); 
    Console.Read(); 
} 

static async Task sayHelloAsync(){   
    await Task.Delay(1000); 
    Console.Write("hello world"); 

} 
7

當C#7.1發佈時,這將使異步主方法可用,並避免在已發佈的答案中需要解決方法。下面的簽名已添加:

public static Task Main(); 
public static Task<int> Main(); 
public static Task Main(string[] args); 
public static Task<int> Main(string[] args); 

這可以讓你寫你這樣的代碼:

static async Task Main(string[] args) 
{ 
    await DoSomethingAsync(); 
} 

static async Task DoSomethingAsync() 
{ 
    //... 
} 
3
class Program 
{ 
    static void Main(string[] args) 
    { 
     test t = new test(); 
     Task.Run(async() => await t.Go()); 
    } 
}