6

这个标题是不是很拗口?...

这是我正在尝试做的事情:

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 */ }
}

我的问题是……调用 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 */

所以......有没有办法IFoo.Bar(){...}在我的类中声明,而不是基本上将两个接口合并为一个?

如果不是,为什么?

4

6 回答 6

5

可以在接口中使用 new 关键字来显式隐藏在它扩展的接口中声明的成员:

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(){}
}
于 2010-12-21T16:35:25.843 回答
1

你没有两个实现IFoo; 你只有一个。
CLR 不区分来自接口树中不同点的接口副本。

特别是没有办法调用IFoo.Bar();你只能打电话IBar.Bar
如果您向 中添加单独的Bar()方法IFoo,您的代码将起作用。

于 2010-12-21T16:20:56.017 回答
1

由于 IFoo 扩展了 Ibar,void IFoo.Bar()并且void IBar.Bar()具有完全相同的功能。您不能两次定义相同的方法,这就是它不起作用的原因。

于 2010-12-21T16:21:45.283 回答
1

你希望行为是什么?每当您调用IFoo.Bar()它时,都会使用 IBar 中的定义,因为它只是一个接口,没有任何单独的概念Bar()new在使用关键字转换为超类时,您只能调用不同的方法,那就是当您覆盖类中的方法时,而不是实现和接口。

当接口相互继承时,子接​​口几乎没有方法的所有权概念。就好像子接口在其中声明了两种方法。


注意:潜在的过度并发症和大脑崩溃!!!谨慎阅读!!!

我相信这是允许的,如果我错了,请纠正我:

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 */ }
}

为了清楚起见,在类名之前留下了 I,但不再有任何接口。调用的方法将取决于对象被转换到的类。

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

哦,你没有使用嵌套接口,它们只是相互继承。嵌套接口是这样的:

interface IBar {
    void Bar();

    interface IFoo {
        void Foo();
    }
}

如您所见,这是完全不同的。这两个接口之间的关系只是一个只能在另一个内部使用。它们是一个复杂且有些棘手的话题。你可以在这里阅读更多。:D

于 2010-12-21T16:23:39.077 回答
1

这只是显式实现的接口方法的编译器约定。你可以这样写:

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

但是,如果您想使用显式实现,那么编译器会坚持使用声明该方法的接口的标识符名称。这是有道理的,IFoo 也可以有一个 Bar() 方法。

于 2010-12-21T16:54:22.170 回答
0

我以前也对此感到沮丧,但我认为关键在于,根据定义,它是一个“显式”实现。除非您将对象强制转换为 IBar,否则 Bar 方法的任何调用都隐含地依赖于对象最终实现 IBar 的事实。

将下面的示例视为您想要的逻辑结论。理论上,FooImpl可以通过实现IFoo显式实现Bar,理论上派生类(FooChild)可以通过继承FooImpl实现IBar。问题在于,这开辟了(至少)两种不同的模棱两可的“显式”实现路径的可能性:

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?
    }
}
于 2011-01-04T15:43:01.927 回答