The goal is to maximize performance in a certain part of the application. Having read some articles of Habr and somewhere once having heard or read something, I began, among other things, to seal classes and methods (and also to turn some small classes into structures). Already zakommitiv, decided in a small application to check, and whether it really gives the result.
class X { public int NonVirtual() => DateTime.Now.Millisecond; public virtual int Virtual() => DateTime.Now.Minute; } class Y : X { public override int Virtual() => DateTime.Now.Millisecond; } class Program { private static volatile int TST = 0; static int Slow(Y x) => x.Virtual(); static int Fast(Y y) => y.NonVirtual(); static void Main(string[] args) { int i = 0; var stopwatch1 = new Stopwatch(); var stopwatch2 = new Stopwatch(); stopwatch1.Start(); var y = new Y(); for (i = 0; i < 100000000; i++) { TST = Fast(y); } stopwatch1.Stop(); Console.WriteLine("Time elapsed: {0}", stopwatch1.Elapsed); stopwatch2.Start(); for (i = 0; i < 100000000; i++) { TST = Slow(y); } stopwatch2.Stop(); Console.WriteLine("Time elapsed: {0}", stopwatch2.Elapsed); Console.ReadKey(); } } The TST field is declared volatile so that the compiler does not optimize calls.
At first I was surprised that there was no difference at all, then the first cycle is faster by a couple of tens of milliseconds, then the second (although the virtual method tables and all that, it is logical to assume that the virtual method should lag a little).
Then I got into IL:
IL_0001: callvirt instance int32 PerformanceTests.X::Virtual() This is a virtual method call. It feels good. Second call:
IL_0001: callvirt instance int32 PerformanceTests.X::NonVirtual() I'm sorry, what? callvirt ? Shouldn't there be a call ? sealed also does not affect the call to the virtual method.
I would like to find out from more experienced colleagues, nevertheless, is there any point in sealing classes in terms of performance? And also, why is the call of a non-virtual function in IL the same as a virtual one?
Update: In the comments, @Grundy wrote that callvirt is because the method is declared in the base class. Rewrote the code so that the base class is now used (i.e. Y is not used). callvirt is called.
sealed. - A1essandrocallinstruction does not check the first argument (this) fornull, and since the C # semantics requires such a check, the compiler usescallvirt. - PetSerAlcalland in one withcallvirt. - PetSerAl pm