C# 用c语言编译/序列化一段代码#
我的目标是编写一个可以编译/序列化任何代码段的类。我在想一些想法,这只是一个概念,我不希望你们写出完整的解决方案,我在想最好的方法。 我想到了两个想法:C# 用c语言编译/序列化一段代码#,c#,reflection,roslyn,C#,Reflection,Roslyn,我的目标是编写一个可以编译/序列化任何代码段的类。我在想一些想法,这只是一个概念,我不希望你们写出完整的解决方案,我在想最好的方法。 我想到了两个想法: 在编译器类中创建一个接口,然后读取接口方法体并使用roslyn将其编译成单独的程序集 序列化表达式树 公元1年。第一概念 public class Runnable : IRunnable { void Run(); } public interface ICodeRunner { void RunCode<T>(
public class Runnable : IRunnable
{
void Run();
}
public interface ICodeRunner
{
void RunCode<T>() where T : IRunnable
}
public class CodeRunner : ICodeRunner
{
public void RunCode<T>() where T : IRunnable
{
MethodInfo mi = typeof(T).GetMethod("Run");
MethodBody mb = mi.GetMethodBody();
// somehow get method body if possible and compile it using roslyn.
// like this:
// string syntaxTree = mb.GetMethodBodyToString() // this method doesn't exist. There must be a way to do that
// CSharpCompilation compilation = CSharpCompilation.Create(
// "abc",
// new[] { syntaxTree },
// new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) },
// new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
// using (var dllStream = new FileStream(@"abc.dll", FileMode.OpenOrCreate))
// using (var pdbStream = new FileStream(@"abc.pdb", FileMode.OpenOrCreate))
// {
// var emitResult = compilation.Emit(dllStream, pdbStream);
// if (!emitResult.Success)
// {
// // emitResult.Diagnostics
// }
// }
}
}
公共类可运行:IRunnable
{
无效运行();
}
公共接口ICodeRunner
{
void RunCode(),其中T:IRunnable
}
公共类CodeRunner:ICodeRunner
{
public void RunCode(),其中T:IRunnable
{
MethodInfo mi=typeof(T).GetMethod(“Run”);
MethodBody mb=mi.GetMethodBody();
//如果可能的话,以某种方式获取方法体并使用roslyn编译它。
//像这样:
//string syntaxTree=mb.GetMethodBodyToString()//此方法不存在。必须有一种方法来实现此目的
//csharpcomilation=csharpcomilation.Create(
//“abc”,
//新[]{syntaxTree},
//新[]{MetadataReference.CreateFromFile(typeof(object.Assembly.Location)},
//新的CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
//使用(var dllStream=newfilestream(@“abc.dll”、FileMode.OpenOrCreate))
//使用(var pdbStream=newfilestream(@“abc.pdb”、FileMode.OpenOrCreate))
// {
//var emitResult=compilation.Emit(dllStream,pdbStream);
//如果(!emitResult.Success)
// {
////emitResult.Diagnostics
// }
// }
}
}
另一种方法是将lambda作为表达式树序列化到文件中,我看到一些库可以这样做。有没有更简单的方法
我的通用用例是创建一个类,该类可以将一些代码(逻辑)和负载序列化为两个单独的文件,通过网络发送,并在不同的机器上运行一段代码+负载。接口为exe文件和通过导线发送的输入文件。对于这个问题,有现成的解决方案吗?这通常不起作用,因为IL中存在无法用C#表示的结构;这正是反编译器面临的问题。对于您的特定用例,您不必担心,如果源代码是C#,但是如果源代码是C#,您已经有了一个完美的序列化格式——它就是源代码。如果只处理在运行时生成的表达式树,因此没有源代码,请参见。一般来说,无论采取何种安全预防措施,通过网络发送任意代码都会让我感到非常不舒服。如果你能为你的有效负载设计一种特定于领域的语言,你会有更多的前期工作,但从长远来看,你会节省维护费用。如果要发送任意代码,根本不必进行反编译——只要按原样传输编译后的可执行文件,或者传输
ildasm
的输出(如果必须具有可读文本)。不需要使用C作为中介。因此,您试图重新发明称为COM/COM+的轮子?这通常无法工作,因为IL中存在无法用C表示的构造;这正是反编译器面临的问题。对于您的特定用例,您不必担心,如果源代码是C#,但是如果源代码是C#,您已经有了一个完美的序列化格式——它就是源代码。如果只处理在运行时生成的表达式树,因此没有源代码,请参见。一般来说,无论采取何种安全预防措施,通过网络发送任意代码都会让我感到非常不舒服。如果你能为你的有效负载设计一种特定于领域的语言,你会有更多的前期工作,但从长远来看,你会节省维护费用。如果要发送任意代码,根本不必进行反编译——只要按原样传输编译后的可执行文件,或者传输ildasm
的输出(如果必须具有可读文本)。不需要使用C#作为中介。那么你想重新发明一个叫做COM/COM+的轮子?