Run dynamically compiled C# code at native speed… how?

后端 未结 3 1159
野的像风
野的像风 2020-12-28 21:56

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

相关标签:
3条回答
  • 2020-12-28 22:33

    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.

    0 讨论(0)
  • 2020-12-28 22:46

    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.

    0 讨论(0)
  • 2020-12-28 22:47

    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"
            },
    
    0 讨论(0)
提交回复
热议问题