深入 CoreCLR 运行时的源代码,我们可以看到一个名为 的静态类RuntimeBootstrapper
,它负责调用我们的入口点:
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;
}
}
我们可以看到,在内部,它调用了ExecuteAsync(args).GetAwaiter().GetResult();
,这在语义上等同于调用Task.Result
,只是AggregationException
我们接收到的异常不是被包装的,而是被解包的。
理解这一点很重要,因为它的发生方式没有“黑魔法”。对于当前版本的 CoreCLR 运行时,允许标记该方法,async Task
因为它被运行时阻塞在调用链的更高位置。
旁注:
深入ExecuteAsync
研究,我们会看到它最终调用:
return bootstrapper.RunAsync(app.RemainingArguments);
在查看内部时,我们看到MethodInfo
了对入口点的实际调用:
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);
}