Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Derived class using the wrong method

I have simplified my code to this

 internal class Program
{
    private static void Main(string[] args)
    {
        Child d = new Child();
        int i = 100;
        d.AddToTotal(i);

        Console.ReadKey();
    }

    private class Parent
    {
        public virtual void AddToTotal(int x)
        {
            Console.WriteLine("Parent.AddToTotal(int)");
        }
    }

    private class Child : Parent
    {
        public override void AddToTotal(int number)
        {
            Console.WriteLine("Child.AddToTotal(int)");
        }

        public void AddToTotal(double currency)
        {
            Console.WriteLine("Child.AddToTotal(double)");
        }
    }
}

The issue is that this calls

public void AddToTotal(double currency)

although I am calling it with an int and it should be using

public override void AddToTotal(int number)

Using the parent returns the expected result.

 Parent d = new Child();
 int i = 100;
 d.AddToTotal(i);

Update:

Thanks to @Jan and @azyberezovsky for pointing me to the specification. I have added a virtual empty method to the base class to get around this for now.

like image 950
Raj Ranjhan Avatar asked Mar 28 '12 14:03

Raj Ranjhan


2 Answers

A member lookup of a name N in a type T is processed as follows:

First, the set of all accessible members named N declared in T and the base types of T is constructed. Declarations that include an override modifier are excluded from the set. If no members named N exist and are accessible, then the lookup produces no match, and the following steps are not evaluated.

Thus when you use variable of Child type

Child d = new Child();
int i = 100;
d.AddToTotal(i);

method public override void AddToTotal(int number) is excluded from set, and we have only one method with name N left. Int is converted implicitly to double, so no errors occured.

like image 153
Sergey Berezovskiy Avatar answered Oct 16 '22 04:10

Sergey Berezovskiy


This answer to this question explains the technical reasons why this happens. I have included the answer inline here for convenience, but all credit is due to tvanfosson.

See the section of the C# Language Specification on Member Lookup and Overload Resolution. The override method of the derived class is not a candidate because of the rules on Member Lookup and the base class method is not the best match based on the Overload Resolution rules.

Section 7.3

First, the set of all accessible (Section 3.5) members named N declared in T and the base types (Section 7.3.1) of T is constructed. Declarations that include an override modifier are excluded from the set. If no members named N exist and are accessible, then the lookup produces no match, and the following steps are not evaluated.

Section 7.4.2:

Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way, as described in detail in the sections listed above. For example, the set of candidates for a method invocation does not include methods marked override (Section 7.3), and methods in a base class are not candidates if any method in a derived class is applicable (Section 7.5.5.1). (emphasis mine)

like image 24
Dan Rigby Avatar answered Oct 16 '22 05:10

Dan Rigby