无法从源代码在 Roslyn 中创建编译

Cannot create a compilation in Roslyn from source code

出于测试目的,我需要从包含源代码的字符串 source 中获取 System.Reflection.Assembly。我正在使用罗斯林:

SyntaxTree tree = CSharpSyntaxTree.ParseText(source);
CSharpCompilation compilation = CSharpCompilation.Create("TestCompilation", new[] { tree });

Assembly assembly = null;
using (var stream = new MemoryStream())
{
    var emitResult = compilation.Emit(stream);
    if (!emitResult.Success)
    {
        var message = emitResult.Diagnostics.Select(d => d.ToString())
            .Aggregate((d1, d2) => $"{d1}{Environment.NewLine}{d2}");

        throw new InvalidOperationException($"Errors!{Environment.NewLine}{message}");
    }

    stream.Seek(0, SeekOrigin.Begin);
    assembly = Assembly.Load(stream.ToArray());
}

如您所见,我在这里的尝试是发出一个 CSHarpCompilation 对象,以便稍后可以获取 Assembly。我正在尝试这样做:

var source = @"
  namespace Root.MyNamespace1 {
    public class MyClass {
    }
  }
";

发出错误

但我在 var emitResult = compilation.Emit(stream) 处失败并输入显示错误的条件。我收到 1 个警告和 3 个错误:

所以我似乎需要添加对 mscorelib 的引用,而且我似乎还需要告诉 Roslyn 我想发出一个 class 库,而不是一个可执行程序集。怎么做?

您缺少对 mscorlib 的元数据引用,您可以通过 CSharpCompilationOptions 更改编译选项。

按如下方式创建您的编译:

var Mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = CSharpCompilation.Create("TestCompilation",
    syntaxTrees: new[] { tree }, references: new[] { Mscorlib }, options: options);

用于从 not-netstandard 代码 创建一个 netstandard 库(在我的例子中,我从 core3.1 创建了一个 netstandard 库) 代码应该是

var compilation = CSharpCompilation.Create("TestCompilation",
    syntaxTrees: new[] { 
        tree 
    }, 
    references: new[] { 
        MetadataReference.CreateFromFile(@"C:\Users\YOURUSERNAME\.nuget\packages\netstandard.library.0.3\build\netstandard2.0\ref\netstandard.dll" 
    }, 
    options: 
        new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

这里的关键是路径。
由于主机代码是 core3.1,因此不能使用 MetadataReference.CreateFromFile(typeof(object).Assembly.Location),因为它引用的是 core3.1 object 而不是 netcore2.0 object.
当引用一个 nuget 包(现在)将它们下载到 %USERPROFILE%\.nuget\packages 文件夹时,它可以从那里加载。这不适用于任何其他用户,因此必须设计不同的解决方案。可以利用 System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile) 但这可能不适用于 CI/CD.

更新:
System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile) 确实适用于 CI/CD。

MetadataReference.CreateFromFile( Path.Combine(
    UserProfilePath, ".nuget", "packages", "netstandard.library", "2.0.3", "build", 
    "netstandard2.0", "ref", "netstandard.dll"))

查看 LehmanLaidun 个版本。