.NET Core 上的 Roslyn 脚本 API:为什么编译器会抱怨 "error CS1501: no overload for WriteLine takes 2 arguments"?

Roslyn Scripting API on .NET Core: why does compiler complain "error CS1501: no overload for WriteLine takes 2 arguments"?

我正在 OSX 上开发一个针对 netcoreapp1.0 的项目,我正在使用 Roslyn 设置脚本,如下所示:

var scriptText = File.ReadAllText(args[0]);

var scriptOptions = ScriptOptions.Default
    .WithReferences(
        typeof(System.Object).GetTypeInfo().Assembly
    );

var script = CSharpScript.Create(scriptText, scriptOptions, typeof(Globals));

var scriptArgs = new string[args.Length-1];
Array.Copy(args, 1, scriptArgs, 0, args.Length-1);

script.RunAsync(new Globals
{ 
    Args = scriptArgs
})
.GetAwaiter().GetResult();

其中 Globals 是:

public class Globals
{
    public string[] Args { get; set; }
}

当我尝试 运行 如下所示的脚本时:

using System;

Console.WriteLine("Args[0]: {0}", Args[0]);

程序因以下异常而终止:

$ dotnet run test.csx
Project BitThicket.DotNet.ScriptTool (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Script error: Microsoft.CodeAnalysis.Scripting.CompilationErrorException: (7,9): error CS1501: No overload for method 'WriteLine' takes 2 arguments
   at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.ThrowIfAnyCompilationErrors(DiagnosticBag diagnostics, DiagnosticFormatter formatter)
   at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.CreateExecutor[T](ScriptCompiler compiler, Compilation compilation, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Scripting.Script`1.GetExecutor(CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Scripting.Script`1.RunAsync(Object globals, Func`2 catchException, CancellationToken cancellationToken)
   at BitThicket.DotNet.ScriptTool.Program.Main(String[] args) in /Users/ben/proj/bt/dotnet-scriptcs/src/BitThicket.DotNet.ScriptTool/Program.cs:line 63

显然 Console 实际上有一个采用 2 个方法的重载。我简要地查看了 CoreFx sources 以查看是否使用了任何奇怪的类型转发或扩展方法技巧,这些技巧可能需要在脚本设置中额外注意,但我没有看到任何不寻常的地方(也许我错过了一些东西).

为什么 Roslyn ScriptBuilder 会抱怨这个?

在 .NET Core 中,Console class 在 System.Console 程序集中,因此您需要将其添加到脚本的引用中:

var scriptOptions = ScriptOptions.Default
    .WithReferences(
        typeof(System.Object).GetTypeInfo().Assembly,
        typeof(System.Console).GetTypeInfo().Assembly
    );

如果您检查 Object 的装配位置,您会看到它是 System.Private.CoreLib.ni.dll。使用 ILSpy,我们可以看到这个程序集只包含一个基本的 Console 实现,方法有 Write(string s)WriteLine(string s)WriteLine()。而 System.Console 程序集包含完整的实现。