2012-10-21 81 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()); 
    } 
}