How does a method hide work in C #? (Part two)

The following program prints

A:C(A,B) B:C(A,B) 

(as it should be)

 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(" + cA() + "," + cB() + ")"); } } public class B : A { public new void Print(C c) { Console.WriteLine("B:C(" + cA() + "," + cB() + ")"); } public void Print(I i) { Console.WriteLine("B:I(" + iA() + ")"); } } 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 replace the keyword 'new' with 'override' in class B as follows:

  public override void Print(C c) 

flash program starts to print:

 A:C(A,B) B:I(A) 

Why?

+13
compiler-construction inheritance c #
Apr 02 '09 at 16:18
source share
4 answers

This is due to how overloaded methods are allowed.

Effectively (simplified), the compiler first considers the declared type of the expression (B) in this case and looks for candidate methods that are first declared in this type. If there are suitable methods (i.e., where all arguments can be converted to method parameter types), then it does not look at any parent types. This means that overridden methods in which the initial declaration is in the parent type do not get the appearance if there are any β€œjust declared” corresponding methods in the derived type.

Here is a slightly simpler example:

 using System; class Base { public virtual void Foo(int x) { Console.WriteLine("Base.Foo(int)"); } } class Derived : Base { public override void Foo(int x) { Console.WriteLine("Derived.Foo(int)"); } public void Foo(double d) { Console.WriteLine("Derived.Foo(double)"); } } class Test { static void Main() { Derived d = new Derived(); d.Foo(10); } } 

This prints Derived.Foo(double) - although the compiler knows that there is a method for matching the parameter of type int , and the argument is type int , and converting from int to int is "better" than converting from int to double , the fact that only the Foo(double) method is initially declared in Derived means that the compiler ignores Foo(int) .

This is very amazing IMO. I can understand why this would be so if Derived did not redefine Foo - otherwise introducing a new, more specific method in the base class might unexpectedly change behavior - but it is clear that Derived here knows about Base.Foo(int) how it redefines it . This is one of the (relatively few) points where I believe that C # developers made the wrong decision.

+8
Apr 02 '09 at 16:27
source share

So,

  public new void Print(C c) { Console.WriteLine("B:C(" + cA() + "," + cB() + ")"); } public void Print(I i) { Console.WriteLine("B:I(" + iA() + ")"); } 

This announces a new printing method. Now, since B inherits from A, you simply call the new method twice. When you override a method, it then changes the method signature when calling A, but when you call the B-signature, then it has its own method signature.

I'm not sure if I explain a clear but good question.

using the new:

A and B get the same implementation of the printing method. A.

using override:

A has a different method signature for B as you did not change the method signature in B to only A.

using the new, he basically ignores this:

  public void Print(I i) { Console.WriteLine("B:I(" + iA() + ")"); } 
+1
Apr 02 '09 at 16:26
source share

That was a great question.
All answers can be found here: http://msdn.microsoft.com/en-us/library/6fawty39(VS.80).aspx

The bottom line is:

... the C # compiler will first try to make a call compatible with versions from [functionName] declared originally on the [derived class]. Overriding methods are not considered declared on the class, they are new implementations of the method declared on the base class. Only if the C # compiler cannot call the method to the original method [Derived class] will try to make a call to the overridden method with the same name and compatible parameters.

Since you have a new Print (I i) method for a derived class that matches the argument "c" (since c implements I), this method takes precedence over the "override" method.

When you mark a method as β€œnew,” both of them are considered implemented in a derived class, and the Print (C c) method more closely matches the β€œc” parameter, so it takes precedence.

+1
Apr 02 '09 at 16:36
source share

This is at least a question about how method overloading works in C #. I think you have identified an interesting situation here ...

In the first case (using the new keyword in the method), the compiler decides to use the Print method overload with a parameter of type C, because it is exactly equivalent to the parameter of the passed parameter (i.e., it does not require an implicit conversion), while I need an implicit conversion to the interface if the compiler has to choose the Print method, which takes an argument of type i - in other words, it chooses a more "obvious" method overload.

In the second case (using the override keyword in the method), the compiler decides to use the Print overload with a parameter of type I, because although you override the overload of the Print(C c) method in class B, it is effectively defined in the parent class A, which makes the Print(I i) method Print(I i) overload is actually the overload of the highest level and therefore the most direct, that is, the first one that the compiler finds.

Hope this helps you understand. Let me know if I need to attach any more items ...

Note. If I am mistaken in saying that the compiler does these things, then please correct me, although this does not really matter for the argument whether it looks like a compiler or CLR / JIT.

0
Apr 02 '09 at 16:37
source share



All Articles