内存编译中的 Roslyn:CS0103:当前上下文中不存在名称“控制台”

Rob*_*Rob 4 c# roslyn .net-core

所以我遇到了这个问题。

我正在尝试在内存中编译代码并通过搜索语法树添加命名空间引用,因此我不会手动添加它们。试图模拟 Visual Studio 可能是如何做到的。

我在编译部门有点不知所措。即使我在阅读语法树时添加对 System 的元数据引用,它也找不到 System.Console。

关键是我希望它自己包含程序集,我不想添加“MetadataReference.CreateFromFile(....,”System.Console”)。

我解释了下面的代码,以便清楚发生了什么。

class App
{
    static void Main(string[] args)
    {
        //creating the syntax tree for the program
        SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
            namespace ns{
                using System;
                public class App{
                    public static void Main(string[] args){
                        Console.Write(""dada"");
                    }
                }


            }");
        //creating options that tell the compiler to output a console application
        var options = new CSharpCompilationOptions(
           OutputKind.ConsoleApplication,
           optimizationLevel: OptimizationLevel.Debug,
           allowUnsafe: true);

        //creating the compilation
        var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), options: options);

        //adding the syntax tree
        compilation = compilation.AddSyntaxTrees(syntaxTree);

        //getting the local path of the assemblies
        var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
        List<MetadataReference> references = new List<MetadataReference>();
        //adding the core dll containing object and other classes
        references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Private.CoreLib.dll")));
        references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "mscorlib.dll")));
        //gathering all using directives in the compilation
        var usings = compilation.SyntaxTrees.Select(tree => tree.GetRoot().ChildNodes().OfType<UsingDirectiveSyntax>()).SelectMany(s => s).ToArray();

        //for each using directive add a metadatareference to it
        foreach (var u in usings)
        {
            references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, u.Name.ToString() + ".dll")));
        }

        //add the reference list to the compilation
        compilation=compilation.AddReferences(references);

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

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

                foreach (Diagnostic diagnostic in failures)
                {
                    Console.Error.WriteLine("{0}: {1}, {2}", diagnostic.Id, diagnostic.GetMessage(), diagnostic.Location);
                }
            }
            else
            {
                ms.Seek(0, SeekOrigin.Begin);
                AssemblyLoadContext context = AssemblyLoadContext.Default;
                Assembly assembly = context.LoadFromStream(ms);
                assembly.EntryPoint.Invoke(null, new object[] { new string[] { "arg1", "arg2", "etc" } });

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Geo*_*ria 5

  • 在 .net 核心中System.Console存在于System.Console.dll. 所以你需要在它上面添加引用
  • 您需要在 上添加引用System.Runtime.dll以正确解析预定义类型:objectbool等等
  • SyntaxNode.ChildNodes()只返回孩子,这意味着它不返回后代节点,所以如果你想得到所有UsingDirectiveSyntax你应该改变你的逻辑。作为一种方式,只需使用SyntaxNode.DescendantNodes()

应用所有建议后,您只会得到如下内容(未更改的部分将被跳过):

  ...
  //adding the core dll containing object and other classes
  references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Private.CoreLib.dll")));
  references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Console.dll")));
  references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Runtime.dll")));

  //gathering all using directives in the compilation
  var usings = compilation.SyntaxTrees.Select(tree => tree.GetRoot().DescendantNodes().OfType<UsingDirectiveSyntax>()).SelectMany(s => s).ToArray();
  ...
Run Code Online (Sandbox Code Playgroud)