【问题标题】:How can you call an explicitly declared interface member in a base class from a subclass?如何从子类调用基类中显式声明的接口成员?
【发布时间】:2013-07-24 20:34:37
【问题描述】:

假设您可以访问实现“IFoo”的基类“MyClass”。 'IFoo' 定义了函数 'int FooValue()' 并且 'MyClass' 显式地实现了它。现在假设您有一个名为“MySubClass”的“MyClass”子类,并且您想覆盖该子类中的“FooValue”,但您还希望子类的实现基于基类实现的结果。

现在通常,只需将实现移动到基类中的受保护函数即可解决此问题,然后我们只需在子类中覆盖该函数即可。做完了。但是我们无权访问基类的源代码。我们仅将其作为对库的引用。那么如何解决呢?

不是重复的(更新:...就像这个)!

这里有一个这样的问题...C#: Property overriding by specifying the interface explicitly...这表明虽然您不能通过普通通道本身覆盖基类的接口,但您可以显式地重新实现子类上的相同接口,其行为就像您正在覆盖该接口(但实际上您是在重新实现它,而不是覆盖它。)也就是说,我想弄清楚的是我如何获得基类的实现。 (这就是为什么恕我直言,这不是那个问题的重复。)

这里是基类的一些伪代码,我们也无法访问代码...

public interface IFoo
{
    int FooValue();
}

public class MyClass : IFoo
{
    int IFoo.FooValue() <-- Explicit implementation requiring a cast to access.
    {
        return 4;
    }
}

这是我们正在尝试做的,但显然这是不允许的,因为您不能像这样使用“base”。

public class MySubClass : MyClass
{
    int IFoo.FooValue()
    {
        int baseResult = ((IFoo)base).FooValue(); <-- Can't use 'base' like this
        return baseResult * 2;
    }
}

那么这可能吗?

【问题讨论】:

  • 我发誓...我搜索和搜索,我什至浏览了所有的“嘿...您可能会问与...相同的问题”,当您输入您的标题,我没有发现任何类似的东西,但令我惊讶的是 bang... 没错,我问的是完全相同的问题,我的被标记为 dup! WTF我找不到吗?我真的搜索过,我发誓!每 d*@$# 次!大声笑!
  • 我不确定是否可以使用一些“诚实”的方式,但您始终可以使用反射来获取并执行您想要的任何私有方法;)

标签: c# interface overriding base


【解决方案1】:

老实说,这个问题没有直接的答案。感觉像是语言的限制。缺少它可能有一些合理的原因。

但是,我可以想到一些不太干净的解决方法。

  1. Reflection. 恕我直言,这里是最简单的选择。真正需要反思的极少数情况之一。

  2. 您自己的接口和基类派生自引用的库。

    //your interface
    public interface IRealFoo : IFoo
    {
        new int FooValue();
    }
    
    //your base class
    public class MyRealClass : MyClass, IRealFoo
    {
        protected virtual int FooValue()
        {
            return ((IFoo)this).FooValue();
        }
    
        int IRealFoo.FooValue()
        {
            return FooValue();
        }
    }
    
    //your child class
    public class MyRealSubClass : MyRealClass
    {
        protected override int FooValue()
        {
            return base.FooValue() * 2;
        }
    }
    

    你处理IRealFooMyRealClass等等而不是IFooMyClass等等。

    IRealFoo x = new MyRealClass();
    IRealFoo y = new MyRealSubClass();
    Console.WriteLine(x.FooValue()); //4
    Console.WriteLine(y.FooValue()); //8
    
  3. 同上,只是抽象类而不是接口。

    同上,但你也可以有一个抽象基类RealFoo,而不是接口IFoo。我认为这是更简单的代码,但不一定是的代码。它完全改变了代码的意图。

    public abstract class RealFoo : MyClass
    {
        public virtual int FooValue()
        {
            return ((IFoo)this).FooValue();
        }
    }
    
    public class MyRealClass : RealFoo 
    {
        public override int FooValue() 
        {
            return base.FooValue();
        }
    }
    
    public class MyRealSubClass : MyRealClass 
    {
        public override int FooValue() 
        {
            return base.FooValue() * 2;
        }
    }
    
    //call it like:
    RealFoo x = new MyRealClass();
    RealFoo y = new MyRealSubClass();
    Console.WriteLine(x.FooValue()); //4
    Console.WriteLine(y.FooValue()); //8
    
  4. 扩展方法以及动态

    public class MyRealClass : MyClass 
    {
        public virtual int FooValue() 
        {
            return ((IFoo)this).FooValue();
        }
    }
    
    public class MyRealSubClass : MyRealClass 
    {
        public override int FooValue() 
        {
            return base.FooValue() * 2;
        }
    }
    
    public static int RealFooValue(this IFoo foo) 
    {
        return ((dynamic)foo).FooValue();
    }
    

    在这种情况下,您可以坚持使用熟悉的IFoo 接口,但您必须调用扩展方法RealFooValue 而不是FooValue。调用FooValue 时,这将与可能的错误结果混淆。我不建议这样做。

    IFoo x = new MyRealClass();
    IFoo y = new MyRealSubClass();
    Console.WriteLine(x.RealFooValue()); //4
    Console.WriteLine(y.RealFooValue()); //8
    
  5. 使用if-else 逻辑打开类型

    public class MySubClass : MyClass
    {
    
    }
    
    public static int RealFooValue(this IFoo foo) 
    {
        var type = foo.GetType();
    
        if (type == typeof(MyClass))
            return foo.FooValue();
        else if (type == typeof(MySubClass))
            return foo.FooValue() * 2; //logic goes here
    
        throw new Exception();
    }
    

    这与上面的问题相同。不推荐。

    IFoo x = new MyClass();
    IFoo y = new MySubClass();
    Console.WriteLine(x.RealFooValue()); //4
    Console.WriteLine(y.RealFooValue()); //8
    

【讨论】:

  • 这不是我想要的。您从函数名称中删除了 IFoo,这意味着在转换为对象时这将不起作用。我希望能够将子类转换为接口,然后调用接口成员的重写版本,同时仍然利用基类的功能。简而言之,我认为这是不可能的。
  • 赞成提供替代方案,但请记住,这里的问题是语言本身
  • @Kjellski 是的。 在我看来,我的备选方案 2 是最好的。事实上,在这种情况下,这是正确的方法。
  • @nawfal 我也这么认为!当我偶然发现 ServiceHostBase 自己托管 WCF 服务时,我发现了这一点。真正困扰我的是,一旦基类显式实现了接口,在这种情况下,IDisposable,您完全没有希望在自己的 dispose 中调用基类,这导致您根本不自己实现 Dispose ...这是理解原因的金矿:pluralsight.com/courses/…
【解决方案2】:

显式接口实现意味着IFoo.FooValue()是私有的 (可以通过反射来检查):

  MethodInfo mi = typeof(MyClass).GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(m => m.Name.EndsWith("IFoo.FooValue")).ToList()[0];

  if (mi.IsPrivate) {
    // And it is private.... 
  } 

所以你不能调用 继承了 IFoo.FooValue()。

可能的途径

  public interface IFoo
  {
      int FooValue();
  }

  public class MyClass : IFoo
  {
      // This (main logic) should be inherited/override 
      protected virtual int CoreFooValue() 
      {
          return 4;
      }

      // Just a non-virtual interface method which is immutable
      int IFoo.FooValue() 
      {
          return CoreFooValue();
      }
  }

  public class MySubClass : MyClass {
      // Logic is changed, interface is not 
      protected override int CoreFooValue() 
      {
          return base.CoreFooValue() * 2;
      }
  }

另见非虚拟接口模式

http://en.wikipedia.org/wiki/Non-virtual_interface_pattern

【讨论】:

  • 谢谢,但在我的问题中,我不仅已经提出了该解决方案(第 2 段),还提出了为什么我们不能在这里使用它。具体来说,我们无法访问 MyClass 的源代码,因此我们无法实现“CoreFooValue”。
猜你喜欢
  • 1970-01-01
  • 2014-04-07
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-02
  • 1970-01-01
相关资源
最近更新 更多