This is the sixteenth part of the .NET Inside Out series. For your convenience you can find other parts in the table of contents in Part 1 – Virtual and non-virtual calls in C#

Today we are going to play with type system to see if we can break it. Let’s take this code:

We create two classes with the same method signatures and different implementation. Next, we have two methods calling Print on types A or B respectively. We then hijack one of the method to point to the other. We call it with instance of type A and this is the output:

So we can see that we are going through method for B but with instance of type A.

So let’s see what happened. We started in PrintWithA with instance of type A. We then jump to PrintWithB. We print to the console and call method Print on type B. However, .NET doesn’t check the type here and just calls the method! In B.Print we print to the console and show the instance type which is A.

What happens if we change Print methods to be virtual? Let’s see:

So there is no difference, even though virtual method uses callvirt instruction under the hood it still doesn’t check the type. However, this time we have called method Print from type A, thanks to dynamic dispatch. Now let’s see this:

This time we add another method Print2 to the B type. The method does exactly the same as Print. Notice, it is not virtual. Output:

So it still works correctly. But let’s now change the method to virtual:

Output:

Why does it crash now? The difference is callvirt instruction. It does the polymorphic dispatch based on the type so it needs to go through the method table. However, there is no method for type A but .NET doesn’t check it. It just reads the memory and jumps to some invalid location.

Takeaway? You can play with types but you need to be very careful.