【问题标题】:.NET C# Explicit implementation of grandparent's interface method in the parent interface.NET C# 父接口中祖父接口方法的显式实现
【发布时间】:2011-05-28 22:25:17
【问题描述】:

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

这就是我想要做的:

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(){...}

如果不是,为什么?

【问题讨论】:

  • 我认为你需要让 IFoo 实现来自 IBar 的方法 Bar
  • @Stephan H - 接口不能实现任何东西;他们只能继承。你的意思可能是别的吗?
  • 一个聪明的程序员知道什么是他必须关心的,什么是无关紧要的。 ...我说对了吗?

标签: c# .net inheritance interface explicit-implementation


【解决方案1】:

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

特别是没有办法调用IFoo.Bar();你只能打电话给IBar.Bar
如果你向IFoo 添加一个单独的Bar() 方法,你的代码就可以工作。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 我并不是建议为 Bar() 添加两个实现。像 class FooImpl: IFoo {void IFoo.Bar(){}} 这样简单的东西不会编译。
    【解决方案3】:

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

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


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

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

    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();
        }
    }
    

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

    【讨论】:

    • 好的,我认为'嵌套接口'就像'接口层次结构'。你是对的,嵌套是一个不同的概念。
    【解决方案4】:

    可以在接口中使用 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(){}
    }
    

    【讨论】:

      【解决方案5】:

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

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

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

      【讨论】:

      • :) 我的意思是:因为 IFoo 没有做任何事情来隐藏或覆盖 Bar(),并且因为 IFoo inherits 从 IBar,我期待编译器将 Bar() 视为在 IFoo 中定义(如果实现是隐式的,但不是针对显式情况,它会这样做)。在我看来,这就像不一致的行为。或者也许我错过了显式接口实现背后的原因。
      • 也许你知道,我不知道。但是请注意我回答中的第一行,它只是一种约定。如果两个 IFoo 和 IBar 都有 Bar 方法并且需要不同的实现,那么这是有意义的。
      【解决方案6】:

      我以前也对此感到沮丧,但我认为关键在于,根据定义,它是一个“显式”实现。除非您将对象强制转换为 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?
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2021-09-14
        • 1970-01-01
        • 1970-01-01
        • 2016-06-20
        • 2021-07-20
        • 2011-06-21
        • 1970-01-01
        • 1970-01-01
        • 2017-06-22
        相关资源
        最近更新 更多