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

时间:2017-03-31 12:38:06

标签: c# .net reflection roslyn roslyn-code-analysis

出于测试目的,我需要从包含源代码的字符串System.Reflection.Assembly获取source。我正在使用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());
}

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

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我要发出一个类库,而不是一个可执行程序集。怎么做?

2 个答案:

答案 0 :(得分:4)

您缺少对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);

答案 1 :(得分:0)

要从非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 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版本。