The following program prints
A:C(A,B) B:C(A,B)
(as it should)
public interface I { string A(); } public class C : I { public string A() { return 'A'; } public string B() { return 'B'; } } public class A { public virtual void Print(C c) { Console.WriteLine('A:C(' + c.A() + ',' + c.B() + ')'); } } public class B : A { public new void Print(C c) { Console.WriteLine('B:C(' + c.A() + ',' + c.B() + ')'); } public void Print(I i) { Console.WriteLine('B:I(' + i.A() + ')'); } } class Program { public static void Main(string[] args) { A a = new A(); B b = new B(); C c = new C(); a.Print(c); b.Print(c); } }
however, if I change keyword ‘new’ to ‘override’ in class B like so:
public override void Print(C c)
all of a sudden program starts to print:
A:C(A,B) B:I(A)
Why?
This is to do with how overloaded methods are resolved.
Effectively (simplified somewhat), the compiler first looks at the declared type of the expression (B) in this case and looks for candidate methods which are first declared in that type. If there are any methods which are appropriate (i.e. where all the arguments can be converted to the method’s parameter types) then it doesn’t look at any parent types. This means that overridden methods, where the initial declaration is in a parent type, don’t get a look-in if there are any ‘freshly declared’ appropriate methods in the derived type.
Here’s a slightly simpler example:
This prints
Derived.Foo(double)– even though the compiler knows there is a matching method with a parameter of typeint, and the argument is typeint, and the conversion frominttointis ‘better’ than the conversion frominttodouble, the fact that only theFoo(double)method is originally declared inDerivedmeans the compiler ignoresFoo(int).This is highly surprising IMO. I can see why it would be the case if
Deriveddidn’t overrideFoo– otherwise introducing a new, more specific, method in the base class could change the behaviour unexpectedly – but clearlyDerivedhere knows aboutBase.Foo(int)as it’s overriding it. This is one of the (relatively few) points where I believe the C# designers made the wrong decision.