我对使用async修饰符进行异步编程并不熟悉。我试图弄清楚如何确保我的控制台应用程序的主要方法实际上是异步运行的。

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = bs.GetList();
    }
}

public class Bootstrapper {

    public async Task<List<TvChannel>> GetList()
    {
        GetPrograms pro = new GetPrograms();

        return await pro.DownloadTvChannels();
    }
}

我知道这不是从“顶层”异步运行的。由于不可能在Main方法上指定异步修饰符,我如何在Main中异步运行代码?


当前回答

不确定这是否是你要找的,但我想等待加载方法。我最终使用main_shows处理程序,并使它异步:

private async void Main_Shown(object sender, EventArgs e)
{
   await myAsyncMethod();
}

其他回答

class Program
{
     public static EventHandler AsyncHandler;
     static void Main(string[] args)
     {
        AsyncHandler+= async (sender, eventArgs) => { await AsyncMain(); };
        AsyncHandler?.Invoke(null, null);
     }

     private async Task AsyncMain()
     {
        //Your Async Code
     }
}

从c# 7.1开始,以下签名对Main方法有效。

public static void Main() { }
public static int Main() { }
public static void Main(string[] args) { }
public static int Main(string[] args) { }
public static async Task Main() { }
public static async Task<int> Main() { }
public static async Task Main(string[] args) { }
public static async Task<int> Main(string[] args) { }

现在你可以执行async/await

static async Task Main(string[] args)
{
    Console.WriteLine("Hello Asyn Main method!");
    await Task.Delay(200);
}

如果你使用的是c# 7.1或更高版本,使用nawfal的答案,只需将Main方法的返回类型更改为Task或Task<int>。如果你不是:

有一个像Johan说的异步任务MainAsync。 调用它的. getawaiter (). getresult()来捕获像do0g所说的底层异常。 像科里说的那样取消支持。 第二个CTRL+C应该立即终止该进程。(谢谢binki !) 处理OperationCancelledException -返回适当的错误码。

最终代码如下:

private static int Main(string[] args)
{
    var cts = new CancellationTokenSource();
    Console.CancelKeyPress += (s, e) =>
    {
        e.Cancel = !cts.IsCancellationRequested;
        cts.Cancel();
    };

    try
    {
        return MainAsync(args, cts.Token).GetAwaiter().GetResult();
    }
    catch (OperationCanceledException)
    {
        return 1223; // Cancelled.
    }
}

private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
    // Your code...

    return await Task.FromResult(0); // Success.
}

你可以用这个简单的构造来解决这个问题:

class Program
{
    static void Main(string[] args)
    {
        Task.Run(async () =>
        {
            // Do any async anything you need here without worry
        }).GetAwaiter().GetResult();
    }
}

这将把你所做的所有事情放在你想要它的线程池(这样你启动/等待的其他任务就不会试图重新加入一个不应该的线程),并等待所有事情都完成后再关闭控制台应用程序。不需要特殊的循环或外部库。

编辑:合并Andrew的未捕获异常的解决方案。

当c# 5 CTP被引入时,你当然可以用async…尽管这样做通常不是个好主意。我相信这是在VS 2013的发布中改变的,成为一个错误。

除非你已经启动了任何其他前台线程,否则你的程序将在Main完成时退出,即使它已经启动了一些后台工作。

你到底想做什么?请注意,你的GetList()方法目前真的不需要是异步的——它添加了一个额外的层,没有真正的原因。它在逻辑上等价于(但比):

public Task<List<TvChannel>> GetList()
{
    return new GetPrograms().DownloadTvChannels();
}