Entry point can be marked with the 'async' modifier on CoreCLR?

后端 未结 1 1634
别那么骄傲
别那么骄傲 2020-12-11 18:05

In Stephan Cleary\'s recent blog post about Async Console Apps on .NET CoreCLR he shows us that in CoreCLR (currently running on Visual Studio 2015, CTP6), the entry point \

相关标签:
1条回答
  • 2020-12-11 18:47

    Diving into the source of the CoreCLR runtime, we can see a static class called RuntimeBootstrapper, which is in charge of invoking our entry point:

    public static int Execute(string[] args)
    {
        // If we're a console host then print exceptions to stderr
        var printExceptionsToStdError = Environment.GetEnvironmentVariable(EnvironmentNames.ConsoleHost) == "1";
    
        try
        {
            return ExecuteAsync(args).GetAwaiter().GetResult();
        }
        catch (Exception ex)
        {
            if (printExceptionsToStdError)
            {
                PrintErrors(ex);
                return 1;
            }
    
            throw;
        }
    }
    

    We can see that internally, it calls ExecuteAsync(args).GetAwaiter().GetResult();, which is semantically equivallent to calling Task.Result, except that instead of recieveing the wrapped AggregationException, we recieve the exception unwrapped.

    This is important to understand, as there is no "black magic" as to how it's happening. For the current version of the CoreCLR runtime, the method is allowed to marked async Task because it's blocked higher up the callchain by the runtime.

    Side Notes:

    Diving into ExecuteAsync, we'll see that it ends up calling:

    return bootstrapper.RunAsync(app.RemainingArguments);
    

    When looking inside, we see that actual MethodInfo invocation of our entry point:

    public static Task<int> Execute(Assembly assembly, string[] args, IServiceProvider serviceProvider)
    {
        object instance;
        MethodInfo entryPoint;
    
        if (!TryGetEntryPoint(assembly, serviceProvider, out instance, out entryPoint))
        {
            return Task.FromResult(-1);
        }
    
        object result = null;
        var parameters = entryPoint.GetParameters();
    
        if (parameters.Length == 0)
        {
            result = entryPoint.Invoke(instance, null);
        }
        else if (parameters.Length == 1)
        {
            result = entryPoint.Invoke(instance, new object[] { args });
        }
    
        if (result is int)
        {
            return Task.FromResult((int)result);
        }
    
        if (result is Task<int>)
        {
            return (Task<int>)result;
        }
    
        if (result is Task)
        {
            return ((Task)result).ContinueWith(t =>
            {
                return 0;
            });
        }
    
        return Task.FromResult(0);
    }
    
    0 讨论(0)
提交回复
热议问题