一尘不染

C#:覆盖返回类型

c#

有没有办法在C#中覆盖返回类型?如果是这样,怎么做,如果不是,为什么,推荐的做事方式是什么?

我的情况是我有一个带有抽象基类及其后代的接口。我想这样做(虽然不行,但是举个例子!):

public interface Animal
{
   Poo Excrement { get; }
}

public class AnimalBase
{
   public virtual Poo Excrement { get { return new Poo(); } }
}

public class Dog
{
  // No override, just return normal poo like normal animal
}

public class Cat
{
  public override RadioactivePoo Excrement { get { return new RadioActivePoo(); } }
}

RadioactivePoo当然继承于Poo

我想为这是为了让那些谁使用Cat对象可以使用Excrement属性,而不必强制转换PooRadioactivePoo而例如Cat还可以是部分Animal列表,用户可能不一定知道或关心他们的放射性便便。希望有道理…

据我所知,编译器至少不允许这样做。所以我想这是不可能的。但是您对此有什么建议呢?


阅读 238

收藏
2020-05-19

共1个答案

一尘不染

我知道已经有很多解决此问题的解决方案,但我想我想出了一个解决现有解决方案中存在的问题的解决方案。

由于以下原因,我对某些现有解决方案不满意:

  • 保罗·特德斯科(Paolo Tedesco)的第一个解决方案: 猫和狗没有共同的基类。
  • Paolo Tedesco的第二种解决方案: 有点复杂且难以阅读。
  • Daniel Daranas的解决方案: 此方法 可行, 但会因大量不必要的强制转换和Debug.Assert()语句而使您的代码混乱。
  • hjb417的解决方案: 此解决方案不允许您将逻辑保留在基类中。在此示例中(调用构造函数),逻辑很简单,但在实际示例中,逻辑并非如此。

我的解决方案

该解决方案应该通过使用泛型和方法隐藏来克服我上面提到的所有问题。

public class Poo { }
public class RadioactivePoo : Poo { }

interface IAnimal
{
    Poo Excrement { get; }
}

public class BaseAnimal<PooType> : IAnimal
    where PooType : Poo, new()
{
    Poo IAnimal.Excrement { get { return (Poo)this.Excrement; } }

    public PooType Excrement
    {
        get { return new PooType(); }
    }
}

public class Dog : BaseAnimal<Poo> { }
public class Cat : BaseAnimal<RadioactivePoo> { }

使用此解决方案,您无需覆盖“狗”或“猫”中的任何内容!这是一些用法示例:

Cat bruce = new Cat();
IAnimal bruceAsAnimal = bruce as IAnimal;
Console.WriteLine(bruce.Excrement.ToString());
Console.WriteLine(bruceAsAnimal.Excrement.ToString());

这将输出:“ RadioactivePoo”两次,表明多态性尚未破坏。

进一步阅读

  • 显式接口实现
  • 新修改器。我没有在此简化的解决方案中使用它,但在更复杂的解决方案中可能需要它。例如,如果您想为BaseAnimal创建一个接口,则需要在“ PooType Excrement”的简化版本中使用它。
  • 出通用修饰符(协方差)。同样,在此解决方案中我没有使用它,但是如果您想执行类似的操作,例如MyType<Poo>从IAnimal返回并MyType<PooType>从BaseAnimal 返回,则需要使用它才能在两者之间进行转换。
2020-05-19