在 OSX 上使用 .NET Core 从代码中调用 Roslyn:"No assembly containing System.Object was found"

Invoking Roslyn from code with .NET Core on OSX: "No assembly containing System.Object was found"

我正尝试在 OSX 上从 .NET Core 中的 C# 调用 Roslyn。

public class Program
{
    public static void Main()
    {
        var cscArgs = CSharpCommandLineParser.Default.Parse(
            new[] { "/target:Library" },
            Directory.GetCurrentDirectory(),
            "/usr/local/share/dotnet/shared/Microsoft.NETCore.App/1.1.0/"
        );
        var refs = cscArgs.MetadataReferences.Select(x => MetadataReference.CreateFromFile(x.Reference, x.Properties));

        foreach (var r in refs)
        {
            Console.WriteLine(r.FilePath);
        }

        var trees = new[]
        {
            CSharpSyntaxTree.ParseText("class Foo {}", cscArgs.ParseOptions)
        };

        var compilation = CSharpCompilation.Create(cscArgs.CompilationName, trees, refs, cscArgs.CompilationOptions);

        using (var peStream = File.OpenWrite("test.dll"))
        {
            var emitResult = compilation.Emit(peStream, null, null, null, cscArgs.ManifestResources, cscArgs.EmitOptions);

            foreach (var d in emitResult.Diagnostics)
            {
                Console.WriteLine(d);
            }
        }
    }
}

当我 运行 这段代码时,(test.dll 保持为空并且) WriteLine 打印出一个 MetadataReference,然后是一个警告和两个编译错误:

/usr/local/share/dotnet/shared/Microsoft.NETCore.App/1.1.0/mscorlib.dll
warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options.
(2,31): error CS0518: Predefined type 'System.Object' is not defined or imported
(2,31): error CS1729: 'object' does not contain a constructor that takes 0 arguments

所以看起来 Compilation 没有获取 mscorlib 引用。 DLL 确实存在于引用的位置。

$ ls /usr/local/share/dotnet/shared/Microsoft.NETCore.App/1.1.0/mscorlib.dll
/usr/local/share/dotnet/shared/Microsoft.NETCore.App/1.1.0/mscorlib.dll

我做错了什么?我怎样才能说服 Roslyn 选择 mscorlib DLL?

如果您尝试为 .NET Core 编译程序集,System.Object 是在 System.Runtime 中定义的,而不是 mscorlib。1 此外,在编译时对于 .NET Core,编译器通常使用参考程序集,而不是实际的运行时二进制文件。

因此,简答:为 System.Runtime.dll 创建 MetadataReference。

var nuget = Environment.GetEnvironmentVariable("HOME") + "/.nuget/packages";
MetadataReference.CreateFromFile(nuget + "/system.runtime/4.3.0/ref/netstandard1.5/System.Runtime.dll")

更长的答案

不过,很有可能您想要的不仅仅是 System.Runtime。查看正在引用哪些库的更简单方法是检查您自己的应用程序的编译。要查看此内容,请添加对 Microsoft.Extensions.DependencyModel 的包引用并检查用于编译和应用程序的所有库。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <PreserveCompilationContext>true</PreserveCompilationContext>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.0.0-*" />
    <PackageReference Include="Microsoft.Extensions.DependencyModel" Version="1.1.0" />
  </ItemGroup>

</Project>
var references = from l in DependencyContext.Default.CompileLibraries
                 from r in l.ResolveReferencePaths()
                 select MetadataReference.CreateFromFile(r);

foreach (var r in references)
{
    Console.WriteLine(r.FilePath);
}

1参见页面底部的 https://docs.microsoft.com/en-us/dotnet/core/api/system.object