Tuesday, March 11, 2008

Buying Wrist-mounted Blades

Virtual, new and override - the differences

When asked what is the difference between new and override, used in a particular case for a property, you can get is the correct answer. New hidden the property in the base class, override, overrides this. Fine, but what does that mean exactly? Now the sensible answers but rather rare.

following example illustrates the workings. Parent is the base class that provides two properties Foo and Bar. Child is a class derived from the parent and the two new properties once with and once with override overrides. In the two instances of class MyClass Child are generated in the first case the declaration is based on the class Parent. The two properties of the two instances are retrieved and printed. Public class MyClass



{public static void Main () {

Parent p = new Child ();
Child c = new Child ();
Console.WriteLine (p.Foo);
Console.WriteLine (p . Bar);
Console.WriteLine (c.Foo);
Console.WriteLine (c.Bar);
Console.ReadLine ();}


} public class Parent {

public string Foo {get {return "ParentFoo";}}
public virtual string Bar {get {return "ParentBar";}}}

public class Child: Parent {

public new string Foo {get {return "ChildFoo";}}
public override string Bar {get {return "ChildBar";}}
}

The insightful Result looks like this:
ParentFoo
ChildBar
ChildFoo
ChildBar

Since two Instances of child produced the expression ParentFoo astonishing for one or the other. Why is that? The answer is in the early-and late binding.

In the case of Foo, the Property on the parent class not declared with virtual. Thus, the early binding is used. This means that the compiler determines at compile time that property is called. Since case declared the variable as a parent is, is in any case (no matter what is effectively an instance is available) the property of the Foo class called Parent and in the second case, the property of the Child class.

In the case of Bar was the property on the base class with virtual, and thus prevents the early binding. That is, which is parsed at run-time instance and the corresponding property of the effective existing class is called (in our case, Child).

And finally a look at the IL code:

.method public hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] class Parent parent,
[1] class Child child)
L_0000: newobj instance void Child::.ctor()
L_0005: stloc.0
L_0006: newobj instance void Child::.ctor()
L_000b: stloc.1
L_000c: ldloc.0
L_000d: callvirt instance string Parent::get_Foo()
L_0012: call void [mscorlib]System.Console::WriteLine(string)
L_0017: ldloc.0
L_0018: callvirt instance string Parent::get_Bar()
L_001d: call void [mscorlib]System.Console::WriteLine(string)
L_0022: ldloc.1
L_0023: callvirt instance string Child:: get_Foo ()
L_0028: call void [mscorlib] System.Console:: WriteLine (string)
L_002d: ldloc.1
L_002e: call instance string virt Parent:: get_Bar ()
L_0033: call void [mscorlib ] System.Console:: WriteLine (string)
L_0038: call string [mscorlib] System.Console:: ReadLine ()
L_003d: pop
L_003e: ret}


Would not expect that when a call early binding and not a call is called virt? Actually, yes. This will callvirt generated so that the class can be tested for zero. The JIT compiler will not implement effectively zero after testing this call in a non-virtual call.