我对使用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();
}

其他回答

最新版本的c# - c# 7.1允许创建异步控制台应用程序。要在项目中启用c# 7.1,你必须将VS升级到至少15.3,并将c#版本更改为c# 7.1或c#最新的次要版本。要做到这一点,请转到项目属性->构建->高级->语言版本。

在此之后,以下代码将工作:

internal class Program
{
    public static async Task Main(string[] args)
    {
         (...)
    }

我将添加一个所有其他答案都忽略了的重要功能:取消。

TPL的一大特点是支持取消功能,控制台应用有内置的取消功能(CTRL+C)。把它们结合在一起很简单。这是我如何构建所有异步控制台应用程序:

static void Main(string[] args)
{
    CancellationTokenSource cts = new CancellationTokenSource();
    
    System.Console.CancelKeyPress += (s, e) =>
    {
        e.Cancel = true;
        cts.Cancel();
    };

    MainAsync(args, cts.Token).GetAwaiter.GetResult();
}

static async Task MainAsync(string[] args, CancellationToken token)
{
    ...
}

c# 7.1(使用vs 2017更新3)引入了async main

你可以这样写:

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

有关c# 7系列的更多详细信息,第2部分:异步主

更新:

你可能会得到一个编译错误:

程序不包含适用于入口点的静态'Main'方法

此错误是由于vs2017.3默认配置为c#7.0而不是c#7.1。

您应该显式地修改项目的设置来设置c#7.1特性。

你可以通过以下两种方法设置c#7.1:

方法一:使用项目设置窗口:

打开项目的设置 选择Build选项卡 点击高级按钮 选择所需的版本 如下图所示:

方法2:手动修改.csproj的PropertyGroup

添加这个属性:

    <LangVersion>7.1</LangVersion>

例子:

    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <PlatformTarget>AnyCPU</PlatformTarget>
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <OutputPath>bin\Debug\</OutputPath>
        <DefineConstants>DEBUG;TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
        <Prefer32Bit>false</Prefer32Bit>
        <LangVersion>7.1</LangVersion>
    </PropertyGroup>    

从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);
}

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

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

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

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