我对使用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中异步运行代码?


当前回答

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
     }
}

其他回答

你也可以在不需要外部库的情况下做到这一点,方法如下:

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var getListTask = bs.GetList(); // returns the Task<List<TvChannel>>

        Task.WaitAll(getListTask); // block while the task completes

        var list = getListTask.Result;
    }
}

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>    
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。Main方法的适当签名已扩展为:

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)
{
    Bootstrapper bs = new Bootstrapper();
    var list = await bs.GetList();
}

在编译时,异步入口点方法将被转换为调用GetAwaitor(). getresult()。

详细信息:https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main。

编辑:

要启用c# 7.1语言特性,您需要在项目上右键单击“Properties”,然后转到“Build”选项卡。在那里,点击底部的高级按钮:

从语言版本下拉菜单中,选择“7.1”(或更高的值):

默认是“最新的主要版本”,它将评估(在撰写本文时)c# 7.0,在控制台应用程序中不支持async main。

在我的情况下,我有一个工作列表,我想从我的主方法异步运行,已经在生产中使用了相当长一段时间,工作良好。

static void Main(string[] args)
{
    Task.Run(async () => { await Task.WhenAll(jobslist.Select(nl => RunMulti(nl))); }).GetAwaiter().GetResult();
}
private static async Task RunMulti(List<string> joblist)
{
    await ...
}