1

Consider the following code:

interface IFooable
{
    void Foo();
}

class Blah : IFooable
{
    public void Foo()
    {
        Console.WriteLine("Hi from 'Blah'");
    }

}

class Bar : Blah, IFooable
{
    public void Foo()
    {
       Console.WriteLine("Hi from 'Bar'");
    }

}

Compiling this code will give the following warning in the compiler:

'Bar.Foo()' hides inherited member 'Blah.Foo()'. Use the new keyword if hiding was intended.

But 'Foo' is an interface method implementation which, by definition, IIRC, is virtual. If you run the following code:

var fooableList = new List<IFooable>();
fooableList.Add(new Blah());
fooableList.Add(new Bar());

foreach (var fooable in fooableList)
{
    fooable.Foo();
}

Surely enough this will output like a virtual call:

Hi from 'Blah'

Hi from 'Bar'

This is quite misleading, moreso if you go ahead and follow the compiler's warning suggestion an mark Bar.Foo as new which has no bearing at all in the output of the program. Yes I know I'm making Bar implement "twice" IFooable but that's still legal code and the resulting warning is completely wrong.

Am I deeply misunderstanding something on how interfaces and method hiding works or is this a corner case compiler warning glitch?

Community
  • 1
  • 1
InBetween
  • 32,319
  • 3
  • 50
  • 90
  • 2
    Foo() is not marked `virtual`. That compiler warning is correct. – Zer0 Sep 08 '14 at 22:07
  • 1
    Where did you get this notion: "But 'Foo' is an interface method implementation which, by definition, IIRC, is virtual"? Perhaps from Java? An interface method implementation is only virtual if you use the virtual keyword. In fact, the error message has nothing to do with your interface -- you could remove the interface altogether and get the same error. – Kirk Woll Sep 08 '14 at 22:27
  • @KirkWoll Of course, if I remove the interface, I get the same warning *but* the output of the program is what I'd expect when hiding `Foo()`: "Hi from 'Blah'" twice. When implementing twice the interface I'm basically getting the same behavior as if `Foo` were virtual. That is my point. About the notion of interface method being virtual, see http://stackoverflow.com/questions/3621410/why-are-c-sharp-interface-methods-not-declared-abstract-or-virtual. I've probably misunderstood it, but the notion comes from there. – InBetween Sep 08 '14 at 22:32

2 Answers2

5

You are doing more than "implenting IFooable twice". Consider the following similar code:

interface IFooable
{
    void Foo();
}

class Blah : IFooable
{
    public void Foo()
    {
        Console.WriteLine("Hi from 'Blah'");
    }
}

class Bar : Blah
{
    public void Foo()
    {
       Console.WriteLine("Hi from 'Bar'");
    }
}

Here you are clearly hiding Blah's implementation of Foo. Making Bar also derive from IFooable does not change this fact. To not hide it, you need to mark it as virtual in Blah itself.

See MSDN.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • Yes I understand this. Your code would output what I'd expect from method hiding: "Hi from 'Blah'" twice. What got me off balance I guess is that implementing `IFooable` twice actually makes the code behave is if the call to `Foo` were virtual. English is not my native language so I'm having a hard time explaining my thoughts. – InBetween Sep 08 '14 at 22:35
  • No its not the same. `IFooable.Foo` would call `Bar.Foo` only if `Foo()` were virtual. The output of your code is "Hi from 'Blah'" twice, the output of my code is "Hi from 'Blah'" and "Hi from 'Bar'" and the output if `Foo` were virtual would be "Hi from 'Blah'" and "Hi from 'Bar'" – InBetween Sep 08 '14 at 22:46
  • Exactly If `Bar` hides `Foo()`, then any call from a `Bar` typed reference *will* resolve to `Bar.Foo()`. *But* any call from a `Blah` typed reference will resolve *always* to `Blah.Foo()` unless its a virtual call. It doesn't matter if the runtime type is really `Bar`, the call is not virtual so it has to resolve to `Blah.Foo()`. The issue is that I'm calling from `IFooable` typed references and the behavior is similiar as if `Foo` were virtual: *runtime* `Blah` typed objects resolve to `Blah.Foo` and runtime `Bar` typed objects resolve to `Bar.Foo` The seemingly same behavior threw me off. – InBetween Sep 08 '14 at 22:57
  • @InBetween You are correct. I now understand your confusion better. As you say, inheriting from `IFooable` makes it "act" virtual, likely because the compiler finds a direct match for `IFooable`'s `Foo` method on the `Bar` object, wheras it doesn't in my code. It doesn't change the fact that you are hiding the base class method, generating the warning. – BradleyDotNET Sep 08 '14 at 23:01
1

Blah class has a Foo method. Bar class has a Blah class. So Blah class has a Foo method. This shouldn't twice implement Interface.

Osman Villi
  • 346
  • 2
  • 24
  • 1
    Somewhat correct, though this could be worded better. Be careful when saying "has a"; inheritance is a "Is a type of" relationship *not* a "Has a" relationship. – BradleyDotNET Sep 08 '14 at 22:19