Run dynamically compiled C# code at native speed... how?
assemblies, c#, compiler-construction, dynamic
Solution
Yes, if you invoke via a `MethodInfo` or a non-specific `Delegate`, then it will indeed be slow. The trick is: don't do that. Various approaches:
for individual methods, go via a basic but typed delegate, such as `Action`, or as a generic catch-all, `Func<object[], object>` - and use `Delegate.CreateDelegate` to create a typed delegate:
Action doSomething = (Action)Delegate.CreateDelegate(typeof(Action), method);
another variant of this is to use the `Expression` API (which has a `.Compile()` method), or `DynamicMethod` (which has `CreateDelegate()`). The key thing: you must get a typed delegate and invoke using typed invoke (not `.DynamicInvoke`).
for more complex cases where you are generating whole types, consider implementing an interface you know about, i.e.
IFoo foo = (IFoo)Activator.CreateInstance(...);
again; after the initial cast (which is very cheap) you can just use static code:
foo.Bar();
Do not use `someDelegate.DynamicInvoke(...)` or `someMethod.Invoke(...)` if you are after any kind of performance.
Problem
I have read several posts on SO about writing and compiling dynamic C# code. For example, this post. I understand it can be done several ways. However, calling the code invoker is slow. I did a simple benchmark, and it's some 500 X slower than calling a native method. What I want to be able to do is the equivalent of loading a DLL and calling one of its methods directly ("natively"), which will give the speed benefits I want. What is the easiest way to go about this? Compile the dynamic code to a dll and then load it? Can it be done in memory? EDIT I don't care about compilation time. Only execution. EDIT 2, 3 Here is the benchmark code I wrote: ``` 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<int, int>) Delegate.CreateDelegate(typeof (Func<int, int>), 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<int, int> 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()); } ```