8

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

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

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

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

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

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

那么这可能吗?

4

2 回答 2

3

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

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

  1. 反射。恕我直言,这里最简单的选择。真正需要反思的罕见情况之一。

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

    你处理IRealFoo,MyRealClass等等而不是IFoo,MyClass等等。

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

    和上面一样,但是你也可以有一个抽象基类RealFoo而不是 interface 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
    
于 2013-10-18T16:07:09.263 回答
0

显式接口实现意味着 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

于 2013-07-25T06:11:02.327 回答