6

That title's a mouthful, isn't it?...

Here's what I'm trying to do:

public interface IBar {
     void Bar();
}
public interface IFoo: IBar {
    void Foo();
}
public class FooImpl: IFoo {
    void IFoo.Foo()   { /* works as expected */ }
    //void IFoo.Bar() { /* i'd like to do this, but it doesn't compile */ }

    //so I'm forced to use this instead:
    void IBar.Bar()   { /* this would compile */ }
}

My problem with this is that it's... inconvenient to call Bar():

IFoo myFoo = new FooImpl();
//myFoo.Bar(); /* doesn't compile */
((IBar)myFoo).Bar(); /* works, but it's not necessarily obvious 
                        that FooImpl is also an IBar */

So... Is there a way to declare IFoo.Bar(){...} in my class, other than basically merging the two interfaces into one?

And, if not, why?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Cristian Diaconescu
  • 34,633
  • 32
  • 143
  • 233
  • I think you need to have IFoo implement the method Bar from IBar – Stefan H Dec 21 '10 at 16:20
  • @Stephan H - Interfaces can't implement anything; they can only inherit. did you mean something else maybe? – Andrew Barber Dec 21 '10 at 16:22
  • A wise programmer learns what he must be concerned about and what doesn't matter a hill of beans in a fartstorm. ...Did I get that right? –  Dec 21 '10 at 16:26

6 Answers6

5

It's possible to use the new keyword in an interface to explicitly hide a member declared in the interface it extends:

public interface IBar
{
    void Bar();
}

public interface IFoo:IBar
{
    void Foo();
    new void Bar();
}

public class Class1 : IFoo
{
    void Bar(){}

    void IFoo.Foo(){}

    void IFoo.Bar(){}

    void IBar.Bar(){}
}
Grokodile
  • 3,881
  • 5
  • 33
  • 59
1

You don't have two implementations of IFoo; you only have one.
The CLR does not distinguish between copies of interfaces that come from different points in the interface tree.

In particular, there is no way to call IFoo.Bar(); you can only call IBar.Bar.
If you add a separate Bar() method to IFoo, your code will work.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
1

Since IFoo extends Ibar, void IFoo.Bar() and void IBar.Bar() are the exact same function. You cannot define the same method twice, that's why it doesn't work.

LaGrandMere
  • 10,265
  • 1
  • 33
  • 41
1

What would you want the behavior to be? Whenever you call IFoo.Bar() its going to use the definition in IBar, because its just an interface and has no separate conception of Bar() whatsoever. You can only have a different method called when casting to a superclass with the new keyword, and that's when you are overriding a method in a class, not implementing and interface.

When interfaces inherit one another, sub-interfaces have little ownership conception of a method. Its as if the sub-interface has both methods declared in it.


Caution: potential over-complication and brain meltdown!!! Read with caution!!!

I believe this is allowed, correct me if I'm wrong:

public class IBar {
     virtual void Bar() {
         //IBar implementation of Bar
     }
}
public class IFoo: IBar {
    new virtual void Foo() {
        //implementation of Foo when currently casted to IFoo
    }
}
public class FooImpl: IFoo {
    new void Foo()   { /* implementation of Foo when cast to FooImpl */ }
    new void Bar()   { /* implementation of Bar when cast to FooImpl */ }
}

left the I's before the class name for clarity, but there are no longer any interfaces. The method that is called will depend on what class the object has been cast to.

IBar b = new IBar();
b.Bar(); //calls IBar.Bar

IFoo f = new IFoo();
f.Bar(); //calls IFoo.Bar
f.Foo(); //calls IFoo.Foo
IBar fooAsBar = (IBar) f;
fooAsBar.Bar(); //calls IBar.Bar

FooImpl fi = new FooImpl();
fi.Bar(); //calls FooImpl.Bar
fi.Foo(); //calls FooImpl.Foo 
IFoo fooImplAsFoo = (IFoo) fi;
fooImplAsFoo.Bar(); //calls IFoo.Bar
fooImplAsFoo.Foo(); //calls IFoo.Foo
IBar fooImplAsBar = (IBar) fi;
fooImplAsBar.Bar(); //calls IBar.Bar

Oh, and you're not using nested interfaces, they are just inheriting from one another. Nested interfaces are like this:

interface IBar {
    void Bar();

    interface IFoo {
        void Foo();
    }
}

As you can see this is completely different. The relationship between the two interfaces is only that one can only be used inside of the other. They are a complicated and somewhat tricky topic. You can read more here. :D

Gordon Gustafson
  • 40,133
  • 25
  • 115
  • 157
1

This is just a compiler convention for explicitly implemented interface methods. You could write it like this:

public class FooImpl : IFoo {
    public void Foo() { /* implements IFoo.Foo */ }
    public void Bar() { /* implements IBar.Bar */ }
}

But if you want to use explicit implementation then the compiler insists you use the identifier name of the interface that declared the method. Which makes sense, IFoo could also have a Bar() method.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • :) What I meant was: since IFoo doesn't do anything to hide or override Bar(), and since IFoo *inherits* from IBar, I was expecting the compiler to treat Bar() as if it was defined in IFoo (which it does, if the implementation is implicit, but not for the explicit case). It seems to me like inconsistent behaviour. Or maybe I'm missing the point on the reasons behind explicit interface implementation. – Cristian Diaconescu Dec 21 '10 at 23:33
  • Maybe you do, I don't know. But keep your eye on the first line in my answer, it is *just* a convention. One that makes sense if *both* IFoo and IBar have a Bar method and require distinct implementations. – Hans Passant Dec 21 '10 at 23:42
0

I've been frustrated by this before, too, but I think the key lies in the fact that it is, by definition, an "explicit" implementation. Unless you're casting your object to IBar, then any invocation of the Bar method is implicitly relying on the fact that the object ultimately implements IBar.

Consider the example below as a logical conclusion to what you want. Theoretically, FooImpl could explicitly implement Bar by virtue of implementing IFoo, and theoretcially, a derived class (FooChild) could implement IBar by virtue of inheriting from FooImpl. The problem is that this opens up a possibility of (at least) two different ambigous "explicit" implementation paths:

public interface IBar {      void Bar(); } 
public interface IFoo: IBar {     void Foo(); }
public class FooImpl: IFoo {  
   void IFoo.Foo()   {  }     
   void IFoo.Bar()   { /* hypothetically, let's suppose this works */ }
   void IBar.Bar()   { /* this could then co-exist with the above.. */  } 
} 
public class FooChild : FooImpl
{
}

public class Owner
{
    public void Stuff()
    {
        FooChild child = new FooChild();
        // This invokes the "explicit" bar method (except not really...)
        ((FooImpl)child).Bar();     // Which version of Bar should be called here?
    }
}
Steven
  • 1,260
  • 9
  • 22