【问题标题】:Cannot create a compilation in Roslyn from source code无法从源代码在 Roslyn 中创建编译
【发布时间】:2017-08-25 17:43:03
【问题描述】:

出于测试目的,我需要从包含源代码的字符串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 个错误:

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

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

【问题讨论】:

  • so 将源字符串动态转换为 c# 代码,然后查询命名空间的..
  • 对于缺少引用 mscorlib 的部分,这可能是一个解决方案:stackoverflow.com/a/49992566/253938

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    为了从非网络标准代码创建一个网络标准库(在我的例子中,我从core3.1创建一个网络标准库)代码应该是

    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 构建。

    【讨论】:

      猜你喜欢
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 2020-01-21
      • 2015-11-04
      • 2017-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多