This is a run-time binding (if it's even the right phrase - I'm not convinced), because even with the variable test2 you could have:
test2 obj = new test3(); // imagine test3 inherits from test2 obj.getStuff(id);
here the variable is test2 , but the object is test3 . You can argue that it may have been sealed , etc., but actually not even virtual instances of (non-static) methods go through the callvirt process. It works well and is very fast. In addition, the callvirt opcode has a null check, which means that your code does not (under the hood) have to constantly check for zeros (which would be necessary if it was a static call)
The only exception to this is the struct , which overrides the object method; The following call is static :
int i = 1; string s = i.ToString();
source share