实现基类的集合 - 我是否需要在派生类中进行这么多的向下转换?

时间:2014-05-26 12:54:27

标签: c# casting

我正在实现一组具有以下模式的类:

 public class Animal {}

 public abstract class AnimalToy
 {
      public AnimalToy(Animal owner)
      {
           Owner = owner;
      }

      public Animal Owner { get; private set; }

      /* Various methods related to all toys that use the Owner property */
 }

 public class Dog: Animal 
 {
      public void Bark() {}
 }

 public class PlasticBone: AnimalToy
 {
      public PlasticBone(Dog owner) : base(owner) {}

      public void Throw()
      {
           ((Dog)Owner).Bark();
      }
 }
  • 我有一个基类AnimalToy,其属性是对另一个基类Animal的引用。
  • 我现在要为Dog课程实施PlasticBoneDog玩具。 PlasticBone是一种仅对狗有效的玩具,实际上构造函数将PlasticBone的所有者限制为Dog类型。
  • PlasticBone有一个方法Throw(),该方法对于该类是唯一的,它使用DogBark())上Dog唯一的方法类。因此,在我可以访问它之前,我需要将通用属性Owner强制转换为Dog

这很好用,但是在我正在研究的这个项目中,这种情况一次又一次出现,导致代码非常难看,派生类的方法充满了基类引用的向下转换。这是正常的吗?或者是否有更好的整体设计更清洁?

3 个答案:

答案 0 :(得分:3)

您可以将AnimalToy类设为通用,这样就可以避免强制转换。

public abstract class AnimalToy<TAnimal> where TAnimal : Animal
{
    public AnimalToy(TAnimal owner)
    {
        Owner = owner;
    }

    public TAnimal Owner { get; private set; }    
}

public class PlasticBone: AnimalToy<Dog>
{
    public PlasticBone(Dog owner) : base(owner) {}

    public void Throw()
    {
        Owner.Bark();
    }
}

值得注意的是((Dog)Owner)不是向上的,它被称为向下倾斜。上流过来了。

答案 1 :(得分:3)

这是修复它的一种方法:

public abstract class Animal 
{
    public abstract void MakeNoise();
}

让狗实现MakeNoise,你可以在你的玩具类中调用它:

public void Throw()
{
    Owner.MakeNoise();
}

答案 2 :(得分:0)

我将尝试在评论中详细阐述讨论,并希望为您提供一个通用的多态解决方案。一般的想法在功能上等同于Carra的建议,但希望这有助于您将这些概念应用到实际问题的领域。

处理你的问题抽象;假设您的抽象基类定义如下:

public abstract class Animal
{
    public abstract void Catch();
}

这是抽象方法语义的转变;你不再有一个抽象的Bark方法,你只需要一个Catch方法,其语义定义为,基本上“对被抛出的东西做出反应”。 Animal的反应完全取决于动物。

因此,您可以像这样定义Dog

public class Dog : Animal
{
    public override void Catch()
    {
        Bark();
    }

    public void Bark()
    {
        // Bark!
    }
}

将您的Throw方法更改为:

public void Throw()
{
    Owner.Catch();
}

现在,Bark特定于Dog,而通用Catch方法适用于所有AnimalAnimal类现在指定其子类必须实现一个方法,该方法对抛出的项目作出反应。事件Dog吠声完全取决于Dog

这是多态性的本质 - 玩具不能确定狗的作用;这取决于狗。所有玩具需要知道的是狗可以抓住它。

更一般地说,我不喜欢有两个扩展独立基类的类是逻辑耦合的(并行层次结构,正如Eric指出的那样),除非其中一个明确地实例化另一个,尽管它不可​​能提供任何实际的在没有看到您的实际解决方案架构的情况下提供建议。