Search code examples
c#inheritanceinterfaceoverridingdefault-interface-member

How could the function defined in the interface with the body be redefined in the inherited function without overriding?


Can somebody explain how same function on same class behaved different?

using System;

public class HelloWorld
{
    public static void Main(string[] args)
    {
        MyUpperScript mAsdfScript = new MyUpperScript();
        IInterface mAsdfInterface = mAsdfScript;
        mAsdfScript.Foo();
        mAsdfInterface.Foo();
    }
}

public class MyUpperScript : MyScript
{
    public void Foo()
    {
        Console.WriteLine("Upper Script");
    }
}
public class MyScript : IInterface
{

}

public interface IInterface
{
    public void Foo()
    {
        Console.WriteLine("Interface");
    }
}

I was expecting it to write "Upper Script" on both Foo() call

Note that if I derive the second class from the interface too it works the way I expect - both print "Upper Script":

// now deriving for the interface too:
public class MyUpperScript : MyScript, IInterface
{
    public void Foo()
    {
        Console.WriteLine("Upper Script");
    }
}

Solution

  • I suspect this is because

    a class does not inherit members from its interface

    (from here), meaning MyScript doesn't actually have a method Foo for MyUpperScript to override. When (and now I'm reallying guessing here...!) you recast the variable to the interface type, the virtual method lookup doesn't know to look for Foo in MyUpperScript anymore, and thus falls back to the default implementation.

    It's still weird to me, though, that it doesn't infer that MyUpperScript implements IInterface indirectly - but that might just be that my mental model of how that works has always been wrong, and there's just no opportunity for that to make anything practical difference until you have default interface members. (Before those, all members of implicitly implemented interfaces would also be inherited from the superclass that implements explicitly.) Personally, I think the language would probably make more sense if this was fixed so that both causes behave as if you've specified the interface explicitly (as in your end note), but I haven't been able to find any text that indicates to me whether this was a conscious decision or not, and what the justification was if it was indeed conscious.

    If you try to use it on directly on MyScript (as below) you should get a compiler error:

    MyScript myScript = new MyScript();
    myScript.Foo(); // compiler error here