Roslyn還出現這麼低階的錯誤,不應該呀!
前幾天對Dora.Interception作了簡單的重構,想提供C#指令碼來定義Interception Policy,毫無疑問微軟提供的編譯平臺Roslyn使C#指令碼化提供了支援。但是沒有想到隨便嘗試了一個簡單的功能就出現了問題,我個人覺得這應該是Roslyn的Bug。但是Roslyn經歷了這麼多次版本的迭代還出現如此低階的錯誤,實在有點說不過去。
閒話少說,我們現在通過幾行簡單的程式碼來重現這個Bug。我們建立了一個.NET Core 2.1的控制檯應用,並新增針對NuGet包”Microsoft.CodeAnalysis.CSharp.Scripting“(版本2.8.2)的依賴。如下所示的是.csproj的完整定義。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.1</TargetFramework> <AssemblyName>App</AssemblyName> <RootNamespace>App</RootNamespace> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <LangVersion>7.3</LangVersion> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="2.8.2" /> </ItemGroup> </Project>
接下來我們編寫了一段簡單的程式。如下面的程式碼片段所示,我們只是採用指令碼的形式建立了一個Foo物件並利用它創建出Bar物件,然後呼叫後者的Print方法而已。
namespace Scripting { public class Foo { } public class Bar { public Foo Foo { get; } public Bar(Foo foo) => Foo = foo; public void Print() => Console.WriteLine(Foo); } class Program { static async Task Main(string[] args) { var options = ScriptOptions.Default .AddReferences(typeof(Program).Assembly) .AddImports("Scripting"); //Success await CSharpScript .Create("var bar = new Bar(new Foo());", options) .ContinueWith("bar.Print()") .RunAsync(); } } }
這段程式碼是沒有問題的,執行之後Print方法輸出的結果可以正常出現在入下所示的控制檯上。
接下來我們將“var bar = new Bar(new Foo());”這行程式碼按照如下的方式拆分成兩行執行。
class Program { static async Task Main(string[] args) { //Fail await CSharpScript .Create("var foo = new Foo();", options) .ContinueWith("var bar = new Bar(foo);") .ContinueWith("bar.Print()") .RunAsync(); } }
在此執行該程式後出現如下所示的“Microsoft.CodeAnalysis.Scripting.CompilationErrorException”異常,並提示“cannot convert from 'Scripting.Foo [App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]' to 'Scripting.Foo [c:\users\jinnan\Source\Repos\App\App\bin\Debug\netcoreapp2.1\App.dll]”。
如下所示的是完整的錯誤資訊:
Unhandled Exception: Microsoft.CodeAnalysis.Scripting.CompilationErrorException: (1,19): error CS1503: Argument 1: cannot convert from 'Scripting.Foo [App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]' to 'Scripting.Foo [c:\users\jinnan\Source\Repos\App\App\bin\Debug\netcoreapp2.1\App.dll]' at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.ThrowIfAnyCompilationErrors(DiagnosticBag diagnostics, DiagnosticFormatter formatter) in /_/src/Scripting/Core/ScriptBuilder.cs:line 104 at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.CreateExecutor[T](ScriptCompiler compiler, Compilation compilation, Boolean emitDebugInformation, CancellationToken cancellationToken) in /_/src/Scripting/Core/ScriptBuilder.cs:line 89 at Microsoft.CodeAnalysis.Scripting.Script`1.GetExecutor(CancellationToken cancellationToken) in /_/src/Scripting/Core/Script.cs:line 359 at Microsoft.CodeAnalysis.Scripting.Script`1.CommonGetExecutor(CancellationToken cancellationToken) in /_/src/Scripting/Core/Script.cs:line 343 at Microsoft.CodeAnalysis.Scripting.Script`1.TryGetPrecedingExecutors(Script lastExecutedScriptInChainOpt, CancellationToken cancellationToken) in /_/src/Scripting/Core/Script.cs:line 407 at Microsoft.CodeAnalysis.Scripting.Script`1.GetPrecedingExecutors(CancellationToken cancellationToken) in /_/src/Scripting/Core/Script.cs:line 370 at Microsoft.CodeAnalysis.Scripting.Script`1.RunAsync(Object globals, Func`2 catchException, CancellationToken cancellationToken) in /_/src/Scripting/Core/Script.cs:line 459 at Scripting.Program.Main(String[] args) in c:\users\jinnan\Source\Repos\App\App\Program.cs:line 31 at Scripting.Program.<Main>(String[] args)