C#动态编译器,在内存中编译时获取标准输出

时间:2019-01-02 13:17:56

标签: c# dynamic-compilation

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

我的代码:

const otherVariableName = 0;

const variableName = otherVariableName || 1;

console.log(variableName);

form.cs的内容:

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();
        }
    }
}

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

1 个答案:

答案 0 :(得分:1)

serviceHost.AddServiceEndpoint(typeof(eTutorWcfService), new NetTcpBinding(SecurityMode.None), ""); 可能使您感到困惑,但是正如我在评论中所写,动态编译的代码不会在自己的进程中运行(也可以实现,但要复杂得多),因此它没有自己的输出。方法main只是当前进程中默认AppDomain中另一个类中的另一个方法。这意味着它将写入外部 hosting 进程的控制台。您将必须使用main捕获该输出。请参见以下linqpad代码段:

Console.SetOut

如果要写入原始标准输出,请先保存,如下所示:

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();
 }