【问题标题】:C# dynamic compiler, get standard output when compile in memoryC#动态编译器,在内存中编译时得到标准输出
【发布时间】:2019-05-29 03:30:03
【问题描述】:

我想获取动态编译代码的标准输出。

我的代码:

using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.IO;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var source = File.ReadAllText("form.cs");

        Dictionary<string, string> providerOptions = new Dictionary<string, string>
                {
                    {"CompilerVersion", "v4.0"}
                };
            CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);

            CompilerParameters compilerParams = new CompilerParameters
            {
                GenerateInMemory = true,
                GenerateExecutable = false,
                ReferencedAssemblies =  {"System.dll" ,"mscorlib.dll"}
        };
            CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
            Assembly assembly = results.CompiledAssembly;
            Type program = assembly.GetType("program.TestPerson");
            MethodInfo main = program.GetMethod("Main");
            var outp= main.Invoke(null, null);
            //Console.WriteLine(outp);
            Console.ReadLine();
        }
    }
}

form.cs的内容:

using System;
namespace program {
    public class TestPerson
    {
         public static void Main()
        {
            var person1 = new Person();
            Console.WriteLine(person1.Name);
        }
    }
}

public class Person
{
    public Person()
    {
        Name = "unknown";
    }
        public Person(string name)
        {
            Name = name;
        }
        public string Name { get;set; }
        public override string ToString()
        {
            return Name;
        }
    }

我真正想要的是在父应用程序中的变量中编译后将 form.cs (Console.WriteLine) 的标准输出,顺便说一下,我不想将代码构建到文件中并将其作为进程运行并读取其输出。 还假设 form.cs 的内容不可编辑。

【问题讨论】:

  • 您想获得 IL 输出吗?或者您想从您的应用程序中捕获您要调用的Console.WriteLine
  • 我可能是错的,但看起来你很困惑。生成的代码不是一个独立的进程,它将作为您当前正在运行的进程的一部分运行,因此它不会有自己的stdout
  • @Icepickle,我想在 form.cs 中捕获 Console.WriteLine 输出
  • @ZorgoZ,是的,我知道,我想你没有得到我的问题,我想做的是动态编译内存中的一段代码,并在不构建的情况下将其输出到变量中任何文件。更具体地说,假设我要编译的代码是一个独立的命令行应用程序,它具有 main() 函数,并将输出写入控制台。但我想在内存中编译它并在变量中获取它在控制台中写入的内容。
  • setting the out 能帮到你吗?

标签: c# dynamic-compilation


【解决方案1】:

main 可能会让您感到困惑,但正如我在评论中所写,您的动态编译代码不会在自己的进程中运行(也可以实现,但要复杂得多),因此它确实没有自己的输出。 main 方法只是当前进程中默认 AppDomain 中的另一个类中的另一个方法。这意味着它将写入您的外部托管进程的控制台。您必须使用Console.SetOut 捕获该输出。请参阅以下 linqpad sn-p:

string source = @"using System;
namespace program {
    public class TestPerson
    {
        public static void Main()
        {
            Console.WriteLine(""TEST"");
        }
    }
}";

void Main()
{
    Dictionary<string, string> providerOptions = new Dictionary<string, string>
            {
                {"CompilerVersion", "v4.0"}
            };
    CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);

    CompilerParameters compilerParams = new CompilerParameters
    {
        GenerateInMemory = true,
        GenerateExecutable = false,
        ReferencedAssemblies = { "System.dll", "mscorlib.dll" }
    };
    CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
    Assembly assembly = results.CompiledAssembly;
    Type program = assembly.GetType("program.TestPerson");
    MethodInfo main = program.GetMethod("Main");

    var sb = new StringBuilder();
    var writer = new StringWriter(sb);
    Console.SetOut(writer);

    var outp = main.Invoke(null, null);

    sb.ToString().Dump(); // this Dump is from linqpad, do what you want with the StringBuilder content 

    Console.ReadLine();
 }

如果要写入原始标准输出,先保存,像这样:

...
var oldOut = Console.Out;
Console.SetOut(writer);

var outp = main.Invoke(null, null);

oldOut.WriteLine($"The result is: {sb.ToString()}");

【讨论】:

  • Console.WriteLine(sb.ToString());不返回任何东西。我做得对吗?
  • @EmilyWong。不,记住,SetOut 之前调用过,输出重定向是有效的。如果您想恢复输出,请在调用SetOut 之前将Console.Out 保存在一个变量中,然后在尝试使用它之前使用它来恢复原始输出。
猜你喜欢
  • 2015-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多