Das liegt daran dass .NET Code nicht in einer virtuellen Maschine läuft.
Bei Java läuft das ganze tatsächlich Just in Time - wenn eine Funktion aufgerufen wird wird erstmal geguckt ob sie schon übersetzt wurde und wenn nein -> Ab durch den Compiler und ausführen. Und das interessanterweise bei jeder neuen Ausführung des Programmes erneut. Deswegen ist Java auch so langsam.
Bei .NET wird der
IL-Code vor der ersten Ausführung vom 'JIT' direkt in für die jeweilige Plattform optimierten, nativen
ASM-Code übersetzt und direkt gegen das .NET Framework (inkl. Garbagecollection etc.) gelinkt und dann ausgeführt. Das bedeutet hier läuft keine VM drumherum die auch noch bei jedem Call erst irgendwo nachgucken muss ob was übersetzt werden muss, sondern das ganze Management ist direkt in der nativen Anwendung integriert. Die Java-Nachteile fallen hier weg, deswegen ist .NET auch entsprechend performant.