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

C# 无法从源代码在Roslyn中创建编译,c#,.net,reflection,roslyn,roslyn-code-analysis,C#,.net,Reflection,Roslyn,Roslyn Code Analysis,出于测试目的,我需要从包含源代码的字符串source中获取System.Reflection.Assembly。我正在使用Roslyn: SyntaxTree tree = CSharpSyntaxTree.ParseText(source); CSharpCompilation compilation = CSharpCompilation.Create("TestCompilation", new[] { tree }); Assembly assembly = null; using (

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

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());
}
正如您所看到的,我在这里的尝试是发出一个
csharpcomilation
对象,以便稍后获得
程序集。我正试图通过以下方式做到这一点:

var source = @"
  namespace Root.MyNamespace1 {
    public class MyClass {
    }
  }
";
发出错误 但是我在
var emitResult=compilation.Emit(stream)
失败,并输入显示错误的条件。我收到1个警告和3个错误:

  • 警告CS8021:找不到RuntimeMetadataVersion的值。未找到包含System.Object的程序集,也未通过选项指定RuntimeMetadataVersion的值
  • (3,34):错误CS0518:未定义或导入预定义类型“System.Object”
  • (3,34):错误CS1729:“对象”不包含接受0个参数的构造函数
  • 错误CS5001:程序不包含适合入口点的静态“Main”方法

因此,我似乎需要添加对
mscorelib
的引用,而且我还需要告诉Roslyn我想要发出一个类库,而不是一个可执行程序集。如何操作?

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

按如下方式创建编译:

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);

要从非netstandard代码创建netstandard库(在我的例子中,我是从core3.1创建netstandard库),代码应该是

var compilation = CSharpCompilation.Create("TestCompilation",
    syntaxTrees: new[] { 
        tree 
    }, 
    references: new[] { 
        MetadataReference.CreateFromFile(@"C:\Users\YOURUSERNAME\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\netstandard.dll" 
    }, 
    options: 
        new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
这里的关键是路径。
由于主机代码是core3.1,因此不能使用
MetadataReference.CreateFromFile(typeof(object).Assembly.Location)
,因为它引用的是core3.1
对象,而不是netcore2.0
对象
参考nuget软件包(现在)时,可将其下载到
%USERPROFILE%\.nuget\packages
文件夹,然后从那里加载。这不适用于任何其他用户,因此必须设计不同的解决方案。可以利用,但这可能不适用于CI/CD

MetadataReference.CreateFromFile( Path.Combine(
    UserProfilePath, ".nuget", "packages", "netstandard.library", "2.0.3", "build", 
    "netstandard2.0", "ref", "netstandard.dll"))
更新
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"))

请参阅构建。

因此,动态地将源字符串转换为c代码,然后查询名称空间的..有关缺少引用的部分
mscorlib
这可能是一个解决方案: