C#动态编译器,在内存中编译时获取标准输出
C# dynamic compiler, get standard output when compile in memory
我想获取动态编译代码的标准输出。
我的代码:
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 的内容不可编辑。
main
可能让你感到困惑,但正如我在评论中所写,你的动态编译代码不会 运行 在它自己的过程中(这也可以实现,但它是复杂得多),因此它没有自己的输出。方法 main
只是当前进程中默认 AppDomain 中另一个 class 中的另一种方法。这意味着它将写入外部 hosting 进程的控制台。您将必须使用 Console.SetOut
捕获该输出。请参阅以下 linqpad 代码段:
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()}");
我想获取动态编译代码的标准输出。
我的代码:
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 的内容不可编辑。
main
可能让你感到困惑,但正如我在评论中所写,你的动态编译代码不会 运行 在它自己的过程中(这也可以实现,但它是复杂得多),因此它没有自己的输出。方法 main
只是当前进程中默认 AppDomain 中另一个 class 中的另一种方法。这意味着它将写入外部 hosting 进程的控制台。您将必须使用 Console.SetOut
捕获该输出。请参阅以下 linqpad 代码段:
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()}");