Does the C # language spec indicate whether method override or shadow is used?

Consider the following source code:

public abstract class SomeBaseClass {

    public abstract void Foo(object a);

}

public class SomeClass<T> : SomeBaseClass {

    public override void Foo(object a) {
        Console.WriteLine("Foo() from SomeBaseClass");
    }

    public void Foo(T a) {
        Console.WriteLine("Foo() from SomeClass");
    }

}

      

The following is not ambiguous as there are two overloads Foo

:

public class Bar : SomeClass<int> { }

var bar = new Bar();
bar.Foo(null);
bar.Foo(24);

      

Does the C # language specification indicate what the expected behavior is in the following example, which is compiled somehow?

public class Baz : SomeClass<object> { }

var baz = new Baz();
baz.Foo(null); // "Foo() from SomeClass"

      

+3


source to share


2 answers


Check out this strange behavior explained by Jon Skeet in his blog post Overload



Inheritance can have a confusing effect. When the compiler goes to look for overloads of an instance method, it looks at the compile-time "target" of the call and looks at the methods declared there. If it can't find anything suitable, it then looks at the parent class ... then the grandparent class, etc. This means that if there are two methods at different levels of the hierarchy, then the "deeper" one will be selected first, even if it is not the "best member of the function" to call. Here's a pretty basic example:

using System;

class Parent
{
    public void Foo(int x)
    {
        Console.WriteLine("Parent.Foo(int x)");
    }   
}

class Child : Parent
{
    public void Foo(double y)
    {
        Console.WriteLine("Child.Foo(double y)");
    }
}


class Test
{
    static void Main()
    {
        Child c = new Child();
        c.Foo(10);
    }
}

      

The purpose of the method call is an expression of type Child, so the compiler considers the Child class first. There is only one method and it is applicable (there is an implicit conversion from int to double), so the one that gets selected. The compiler does not consider the Parent method at all.

The reason for this is to reduce the risk of a brittle base class problem, where introducing a new method into the base class can cause problems for consumers of classes derived from it. Eric Lippert has various posts about the brittle base class issue that I can highly recommend .

There is one aspect of this behavior that is particularly surprising. What is considered a method declared in a class? It turns out that if you override a base class method in a child class, it doesn't count as declaring it. Let's pick up our example a little:

using System;

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

class Child : Parent
{
    public override void Foo(int x)
    {
        Console.WriteLine("Child.Foo(int x)");
    }   

    public void Foo(double y)
    {
        Console.WriteLine("Child.Foo(double y)");
    }
}


class Test
{
    static void Main()
    {
        Child c = new Child();
        c.Foo(10);
    }
}

      

Now it looks like you are trying to call Child.Foo (int x) in my opinion - but the code above will indeed print Child.Foo (double y). The compiler ignores the override method on the child.

Given this oddity, my advice is to avoid inheritance-bound overloading. ...

+3


source


https://msdn.microsoft.com/en-us/library/aa691331%28VS.71%29.aspx



"First, a set of all available (section 3.5) elements is created with the name N, declared in T, and the base types (section 7.3.1). Declarations containing the override modifier are excluded from the set . If none of the members named N exists and is not available, then the search will not match and the next steps will not be evaluated.

0


source







All Articles