Type of execution during a call to a compilation type method

C # 4.0 specifications:

When a virtual method is called, the type of instance execution for which this call takes place determines the actual method to call. When invoking a non-virtual method, the determining factor is the type of instance compilation time.

At first I thought it was related to initialization. For example, for two initializations:

BaseClass bcDerived = new Derived(); vs BaseClass bcBase = new BaseClass();

and overload in helper class:

 public virtual void Method(Derived d) { Console.WriteLine("Result = derived called"); } public virtual void Method(BaseClass d) { Console.WriteLine("Result = base called"); } 

Method In this case, the virtual does not affect invokation. Regardless of what virtual marked, the least derived overload is invoked. Only during override in the Derived class does the method call change.

So what do the "runtime type" and the "compile time type" mean? How do they affect method invocation?

+7
source share
3 answers

It depends more on virtual and non-virtual methods and on how the call is made. The part of the specification that you are quoting handles method calls to call the variable bcDerived.SomeMethod() that does not call foo.SomeMethod(bcDerived) .

The specification you are quoting refers to the case where you have non-virtual methods:

 public class A { public void Foo() { Console.WriteLine("A.Foo"); } public virtual void Bar() { Console.WriteLine("A.Bar"); } } public class B : A { public new void Foo() { Console.WriteLine("B.Foo"); } public override void Bar() { Console.WriteLine("B.Bar"); } } 

Then the called method will be determined by the compiler at compile time:

 A someInst = new B(); someInst.Foo(); 

This will call A.Foo() , regardless of which subclass A is referenced by someInst , since this is not a virtual method.

If you have a virtual method, the callvirt statement is set by the compiler, which moves the solution at run time. It means that:

  someInst.Bar(); 

Call B.Bar() , not A.Bar() .

In your case, you do not call the virtual method (in the sense referred to in the specification), but when you execute the standard method. 7.5.3 C # Spec describes in detail overload resolution. In your case, the argument list ( bcDerived ) is checked by the compiler and treated as a BaseClass type. The β€œbest fit” for this would be the public virtual void Method(BaseClass d) , since the parameter list directly matches the argument list, which is why it is used at compile time.

Enabling method overloads, if you look at the specification, does not directly accept virtual method calls - it only looks at implicit conversions between types.

+5
source

In this case, the argument compilation time type will always be used to determine the overload for the call. Virtual dispatch depends on the type of runtime of the object on which the method is called.

The compilation time type is the type of the object as determined by the compiler, and the execution type is the actual type when the code is executed. To use your example:

 BaseClass bcDerived = new Derived() 

The compile-time type is BaseClass , while the execution type will be Derived .

To understand the consequences, we need to expand the class a bit:

 class BaseClass { public virtual void SomeMethod() { Console.WriteLine("In base class"); } } class Derived : BaseClass { public override void SomeMethod() { Console.WriteLine("In derived class"); } } 

Now the call to bcDerived.SomeMethod() will depend on the type of runtime bcDerived regarding whether the BaseClass implementation will be called or the Derived implementation will be implemented.

Eric Lippert wrote a very good three-part series about virtual sending to .Net (of which the first part is here ), I would highly recommend reading them in order to better understand the subject.

+1
source
 Using these two classes as examples: public class Parent { public void NonVirtual() { Console.WriteLine("Nonvirtual - Parent"); } public virtual void Virtual() { Console.WriteLine("Virtual - Parent"); } } public class Child : Parent { public override void Virtual() { Console.WriteLine("Virtual - Child"); } public void NonVirtual() { Console.WriteLine("Nonvirtual - Child"); } } 

The difference between virtual and non-virtual is most clearly seen through this code:

 Parent childAsParent = new Child(); childAsParent.Virtual(); childAsParent.NonVirtual(); 

Fingerprints:

  Virtual - Child
 Nonvirtual - Parent 

In the case of a virtual method at runtime, it sees that the type childAsParent is a child, and thus performs a child definition of Virtual . For a non-virtual method, he sees that the compile time type is Parent and ignores the fact that the actual instance is Child and uses the parent implementation.

Virtual not used to determine which method overload is used based on parameter types. Determining which method overload for the call is always performed at compile time (unless dynamic used), never at run time, so it will always select the Method overload in your example based on the type of compilation time variable.

0
source

All Articles