Microsoft.CodeAnalysis:使用Newtonsoft JObject编译动态代码时出错

时间:2019-02-27 13:50:03

标签: c# json.net roslyn dynamic-code microsoft.codeanalysis

我遇到一个无法解决的奇怪问题。我在大多数情况下已经成功地编译了动态程序集,但是在编译以下行时遇到了一个奇怪的问题:

返回新的JObject()。Properties()。ElementAt(0).Value();

出现错误:

System.ApplicationException: 'Error creating dynamic code assembly 'IEnumerable<JProperty>' does not contain a definition for 'ElementAt' and no accessible extension method 'ElementAt' accepting a first argument of type 'IEnumerable<JProperty>' could be found (are you missing a using directive or an assembly reference?) '

当在项目中作为真实类创建但在动态程序集中创建时,发射的文本输出工作正常。该项目是一个asp.net core 2.2项目,它引用了一个创建动态程序集的程序集。

以下是创建程序集的代码:

public static class Class2
{
    public static Assembly GenerateAssenbly()
    {

        //generate the code
        StringBuilder sb = new StringBuilder("");
        sb.AppendLine("using System;");
        sb.AppendLine("using System.Linq;");

        sb.AppendLine("using Newtonsoft.Json;");
        sb.AppendLine("using Newtonsoft.Json.Linq;");

        sb.AppendLine("namespace test");
        sb.AppendLine("{");
        sb.AppendLine($"class Parser");
        sb.AppendLine("{");

        sb.AppendLine($"public object test() ");
        sb.AppendLine("{");
        sb.AppendLine("return new JObject().Properties().ElementAt(0).Value<string>();");
        sb.AppendLine("}");

        sb.AppendLine("}"); //class
        sb.AppendLine("}"); //namespace

        SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sb.ToString());

        var runtimeAssemblyDirectory = Path.GetDirectoryName(typeof(object).Assembly.Location);
        string assemblyName = Path.GetRandomFileName();
        MetadataReference[] references = new MetadataReference[]
        {
            MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
            MetadataReference.CreateFromFile(Assembly.GetExecutingAssembly().Location),
            MetadataReference.CreateFromFile(Path.Combine(runtimeAssemblyDirectory, "System.Runtime.dll")),
            MetadataReference.CreateFromFile(Path.Combine(runtimeAssemblyDirectory, "mscorlib.dll")),
            MetadataReference.CreateFromFile(Path.Combine(runtimeAssemblyDirectory, "System.dll")),
            MetadataReference.CreateFromFile(Path.Combine(runtimeAssemblyDirectory, "netstandard.dll")),
            MetadataReference.CreateFromFile(Path.Combine(runtimeAssemblyDirectory, "System.Core.dll")),

            MetadataReference.CreateFromFile(typeof(JObject).GetTypeInfo().Assembly.Location),
        };

        CSharpCompilation compilation = CSharpCompilation.Create(
            assemblyName,
            syntaxTrees: new[] { syntaxTree },
            references: references,
            options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));


        Debug.Print(sb.ToString()); // copy output to a class to test

        using (var ms = new MemoryStream())
        {
            EmitResult result = compilation.Emit(ms);

            if (!result.Success)
            {
                throw new ApplicationException($"Error creating dynamic code assembly " + GetCompilerResultsErrors(result));
            }
            else
            {
                return Assembly.Load(ms.GetBuffer());
            }
        }
    }

    private static string GetCompilerResultsErrors(EmitResult result)
    {
        StringBuilder sb = new StringBuilder();

        IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
            diagnostic.IsWarningAsError ||
            diagnostic.Severity == DiagnosticSeverity.Error);

        foreach (Diagnostic diagnostic in failures)
        {
            sb.AppendLine(diagnostic.GetMessage());
        }

        return sb.ToString();
    }
}

(显示的代码并非旨在用于工作目的,因此已简化为演示问题)

预先感谢

1 个答案:

答案 0 :(得分:1)

解决方案是添加特定的引用:

MetadataReference.CreateFromFile(Path.Combine(runtimeAssemblyDirectory, "System.Linq.Expressions.dll")),
MetadataReference.CreateFromFile(Path.Combine(runtimeAssemblyDirectory, "System.Linq.dll")),