3

I faced unexpected (unexpected for me) method call in classes described like this:

class Program
{
    static void Main(string[] args)
    {
        int param = 5;
        var item = new Derived();
        item.DoWork(param);
        Console.ReadLine();
    }
}

class Derived : Base
{
    public override void DoWork(int param) { Console.WriteLine("derived int"); }

    public new void DoWork(double param) { Console.WriteLine("derived double"); }
}

class Base
{
    public virtual void DoWork(int param) { Console.WriteLine("base int"); }

    public virtual void DoWork(double param) { Console.WriteLine("base double"); }
}

I would expect that output is: "derived int", but strangely it's "derived double". If I change new keyword to override then I see expected output"derived int". Seems I miss something related to inheritance logic.
Is there somebody can explain this behavior?

Alexey Klipilin
  • 1,866
  • 13
  • 29
  • 3
    Look at this [thread](https://stackoverflow.com/a/39233807/4728685) and John Skeet explanation – Pavel Anikhouski Sep 23 '19 at 09:37
  • The "new" modifier instructs the compiler to use your child class implementation instead of the parent class implementation. Any code that is not referencing your class but the parent class will use the parent class implementation. So when you use the "new" you are saying to use that implementation. See this [thread](https://stackoverflow.com/questions/1399127/difference-between-new-and-override) – Pedro Brito Sep 23 '19 at 09:38
  • @PavelAnikhouski, why not vote for duplicate then, it is appropriate, seeing new is just an indication that not overriding the original method was intended from the developers view for the compiler (that came out overly complicated) – Icepickle Sep 23 '19 at 09:52

1 Answers1

0

That's not an inheritance issue, rather an overload one. Here's how the compiler resolves overloaded method invocations:

  1. First, the compiler looks at the most derived type
  2. The compiler adds to the pool of candidate methods only the ones for which type inference succeds that AREN'T declared in a base class (so override methods aren't added to the pool, while newly declared methods are)
  3. If there are no candidates to choose from in the pool, the compiler looks at the current type's base type and goes back to step 2. If the current type does not have a base type, a compile-time error occurs
  4. If there is at least one valid candidate in the method pool, the compiler then picks the method to call using its overload resolution rules
  5. If more than a single method can be identified for invokation from step 4, then a compile-time error occurs

In this case, after calling DoWork from the derived class, on step 2 the compiler only adds the method flagged with new to the pool. On the other hand, if you call the method from the base class as shown below, you get the output you would expect:

int param = 5;
Base item = new Derived();
item.DoWork(param);

// output: derived int

Source

sephiroth
  • 896
  • 12
  • 22