以原生速度运行动态编译的C#代码……怎么样?

我已经阅读了几篇关于编写和编译动态C#代码的post。 例如, 这篇文章 。 我知道它可以通过几种方式完成。

但是,调用代码调用程序很慢。 我做了一个简单的基准测试,它比调用本机方法慢了约500倍。

我想要做的是相当于加载DLL并直接调用其中一个方法(“本机”),这将提供我想要的速度优势。

最简单的方法是什么? 将动态代码编译为dll然后加载它? 可以在记忆中完成吗?

编辑

我不关心编译时间。 只执行。

编辑2,3

这是我写的基准代码:

public static int Execute(int i) { return i * 2; } private void button30_Click(object sender, EventArgs e) { CSharpCodeProvider foo = new CSharpCodeProvider(); var res = foo.CompileAssemblyFromSource( new System.CodeDom.Compiler.CompilerParameters() { GenerateInMemory = true, CompilerOptions = @"/optimize", }, @"public class FooClass { public static int Execute(int i) { return i * 2; }}" ); var type = res.CompiledAssembly.GetType("FooClass"); var obj = Activator.CreateInstance(type); var method = type.GetMethod("Execute"); int i = 0, t1 = Environment.TickCount, t2; //var input = new object[] { 2 }; //for (int j = 0; j < 10000000; j++) //{ // input[0] = j; // var output = method.Invoke(obj, input); // i = (int)output; //} //t2 = Environment.TickCount; //MessageBox.Show((t2 - t1).ToString() + Environment.NewLine + i.ToString()); t1 = Environment.TickCount; for (int j = 0; j < 100000000; j++) { i = Execute(j); } t2 = Environment.TickCount; MessageBox.Show("Native: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString()); var func = (Func) Delegate.CreateDelegate(typeof (Func), method); t1 = Environment.TickCount; for (int j = 0; j < 100000000; j++) { i = func(j); } t2 = Environment.TickCount; MessageBox.Show("Dynamic delegate: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString()); Func funcL = Execute; t1 = Environment.TickCount; for (int j = 0; j < 100000000; j++) { i = funcL(j); } t2 = Environment.TickCount; MessageBox.Show("Delegate: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString()); } 

是的,如果您通过MethodInfo或非特定的Delegate调用,那么它确实会很慢。 诀窍是: 不要那样做 。 各种方法:

  • 对于单个方法,通过基本但类型化的委托(例如Action )或作为通用的catch-all, Func – 并使用Delegate.CreateDelegate创建类型化的委托:

     Action doSomething = (Action)Delegate.CreateDelegate(typeof(Action), method); 

    另一种变体是使用Expression API(具有.Compile()方法)或DynamicMethod (具有CreateDelegate() )。 关键是:您必须获取一个类型化委托并使用类型化调用(而不是.DynamicInvoke )进行调用。

  • 对于生成整个类型的更复杂的情况,请考虑实现您知道的接口,即

     IFoo foo = (IFoo)Activator.CreateInstance(...); 

    再次; 在初始演员(非常便宜)之后你可以使用静态代码:

     foo.Bar(); 

如果您遇到任何类型的性能,请不要使用someDelegate.DynamicInvoke(...)someMethod.Invoke(...)

除了Marc的建议,你可以通过指定“optimize”编译器选项来提高速度:

 var res = foo.CompileAssemblyFromSource( new System.CodeDom.Compiler.CompilerParameters() { GenerateInMemory = true, CompilerOptions = "/optimize" }, 

认为值得展示所有潜在选项的外观及其性能特征。 给出以下帮助程序类和函数:

 public void Test(Func func) { var watch = new Stopwatch(); watch.Start(); for (var i = 0; i <= 1000000; i++) { var test = func(); } Console.WriteLine(watch.ElapsedMilliseconds); } public class FooClass { public int Execute() { return 1;}} 

设置和执行:

 using (Microsoft.CSharp.CSharpCodeProvider foo = new Microsoft.CSharp.CSharpCodeProvider()) { var res = foo.CompileAssemblyFromSource( new System.CodeDom.Compiler.CompilerParameters() { GenerateInMemory = true }, "public class FooClass { public int Execute() { return 1;}}" ); var real = new FooClass(); Test(() => real.Execute()); // benchmark, direct call var type = res.CompiledAssembly.GetType("FooClass"); var obj = Activator.CreateInstance(type); var method = type.GetMethod("Execute"); var input = new object[] { }; Test(() => (int)method.Invoke(obj, input)); // reflection invoke dynamic dyn = Activator.CreateInstance(type); Test(() => dyn.Execute()); // dynamic object invoke var action = (Func)Delegate.CreateDelegate(typeof(Func), null, method); Test(() => action()); // delegate } 

结果是:

 8 // direct 771 // reflection invoke 41 // dynamic object invoke 7 // delegate 

那么在那些你不能使用代表的情况下(如果你还不够了?),你可以试试dynamic