I found a Microsoft blog on this ( Generating Dynamic Methods ) and compared performance between a static method, a compiled expression tree, and IL injection.
Here is the code:
static void Main(string[] args) { double acc = 0; var il = ILFact(); il.Invoke(1); var et = ETFact(); et(1); Stopwatch sw = new Stopwatch(); for (int k = 0; k < 10; k++) { long time1, time2; sw.Restart(); for (int i = 0; i < 30000; i++) { var result = CSharpFact(i); acc += result; } sw.Stop(); time1 = sw.ElapsedMilliseconds; sw.Restart(); for (int i = 0; i < 30000; i++) { double result = il.Invoke(i); acc += result; } sw.Stop(); time2 = sw.ElapsedMilliseconds; sw.Restart(); for (int i = 0; i < 30000; i++) { var result = et(i); acc += result; } sw.Stop(); Console.WriteLine("{0,6} {1,6} {2,6}", time1, time2, sw.ElapsedMilliseconds); } Console.WriteLine("\n{0}...\n", acc); Console.ReadLine(); } static Func<int, int> ILFact() { var method = new DynamicMethod( "factorial", typeof(int), new[] { typeof(int) } ); var il = method.GetILGenerator(); var result = il.DeclareLocal(typeof(int)); var startWhile = il.DefineLabel(); var returnResult = il.DefineLabel();
Here are three runs made on the i7-920. Build - Release x64
583 542 660 577 578 666 550 558 652 576 575 648 570 574 641 560 554 640 558 551 650 561 551 666 624 638 683 564 581 647 -3778851060... 482 482 557 489 490 580 514 517 606 541 537 626 551 524 641 563 555 631 552 558 644 572 541 652 591 549 652 562 552 639 -3778851060... 482 482 560 507 503 591 525 543 596 555 531 609 553 556 634 540 552 640 579 598 635 607 554 639 588 585 679 547 560 643 -3778851060...
Medium: 554,549,634
Static versus IL - IL 1% faster (!) I donβt know why, although
Static vs ET - static 14% faster than expression tree
EDIT (February 2014) . I just ran the code above (with very slight changes) on .NET 4.5 and faster than the CPU and got new result sets: Method / ET - 9%, method / IL - 4%
Therefore, the previous results are no longer valid - calling a static method is always faster .
* Not sure if this is new hardware (i7-3820) or new .NET, or maybe I did something wrong in the old test. *
Another interesting result is that in 32-bit the same code shows absolutely NO difference between 3.
Method IL ET -------------------- 368 382 399 367 382 399 367 382 399 367 382 400 367 383 400 367 382 399 367 383 399 367 382 399 367 382 399 367 383 400 367 382 399 367 382 399 367 382 399 367 382 399 367 383 400 367 382 400 367 383 399 367 383 400 367 382 399 367 382 400 -7557702120... -------------------- 367.05 382.30 399.35