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 c
Thought it was worth showing how all potential options looked and their performance characteristics. Given the following helper classes and functions:
public void Test(Func<int> 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;}}
Set up and execution:
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<int>)Delegate.CreateDelegate(typeof(Func<int>), null, method);
Test(() => action()); // delegate
}
The results are:
8 // direct
771 // reflection invoke
41 // dynamic object invoke
7 // delegate
So in those cases where you can't use delegates (if you don't know enough?), you can try dynamic
.
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.
Besides Marc's advice you could improve speed by specifying the "optimize" compiler option:
var res = foo.CompileAssemblyFromSource(
new System.CodeDom.Compiler.CompilerParameters()
{
GenerateInMemory = true,
CompilerOptions = "/optimize"
},