【问题标题】:Why can't I access methods specific to my child class?为什么我不能访问特定于我的子类的方法?
【发布时间】:2014-05-16 14:16:02
【问题描述】:

在 C# 中,我有一个带有公共成员的父类。我想派生父类,然后派生public成员的类,从而创建和访问新的方法,如下...

    public class Animal { }
    public class Sheep : Animal {
        public void makeALamb() { }
    }
    public class Farm
    {
        public Animal myAnimal;
    }
    public class SheepFarm : Farm {
        public void SheepFarm() {
            this.myAnimal = new Sheep();
            this.myAnimal.makeALamb();
        }
    }

此代码无法编译。 “Animal 不包含 makeALamba() 的定义”。但我想做的是多态的本质,不是吗?我错过了什么?我非常期待找到答案。

提前致谢!

【问题讨论】:

    标签: c# object polymorphism


    【解决方案1】:

    因为myAnimalAnimal 类型。因此,它只能访问Animal... 的成员,而Animal 没有方法makeALamb

    此处作业的右侧:

    this.myAnimal = new Sheep();
    

    ..说它是什么。左侧说明您的代码将其视为什么。你作业的左边是:

    public Animal myAnimal;
    //     ^^^^^^
    

    现在..假装你已经尝试过的事情是可能的..考虑一下:

    this.myAnimal = new Snake();
    this.myAnimal.makeALamb(); // what does it call here?
    
    this.myAnimal = new Giraffe();
    this.myAnimal.makeALamb(); // what here?
    

    ..当您在 Snake 实例上调用 makeALamb 时会发生什么? ...

    【讨论】:

      【解决方案2】:

      如果我猜对了您打算做什么,请考虑使用泛型:

      public class Farm<TAnimal> where TAnimal : Animal
      {
          public TAnimal myAnimal;
      }
      
      public class SheepFarm : Farm<Sheep>
      {
          public void SheepFarm()
          {
              this.myAnimal = new Sheep();
              this.myAnimal.makeALamb();
          }
      }
      

      【讨论】:

        【解决方案3】:

        makeALamb()Sheep 的方法,而不是AnimalSheep 派生自 Animal,而不是相反。

        【讨论】:

          【解决方案4】:

          this.myAnimal定义AnimalAnimal 没有 makeALamb 方法。既然您 Sheep 放入this.myAnimal,您可以 转换它:

          ((Sheep)this.myAnimal).makeALamb();
          

          这实际上是说:“将this.myAnimal 视为Sheep 并在其上调用makeALamb()”。如果this.myAnimal 在运行时真的不是一只羊,你会得到一个异常。

          【讨论】:

            【解决方案5】:

            这个想法是你的 Animal 可以被实例化为 Sheep,但它只会处理 Animal 上定义的成员。很简单:Sheep 是 Animal,但 Animal 不是 Sheep,所以 Animal 不能 makeALamb() :)

            【讨论】:

              【解决方案6】:

              如果您想访问makeALamb 方法,您必须将您的Animal 实例转换为Sheep

              public void SheepFarm() 
              {
                  this.myAnimal = new Sheep();
                  ((Sheep)this.myAnimal).makeALamb();
              }
              

              没有演员myAnimal被认为是Animal的类型,因此您只能访问Animal的成员和Animal的基类成员(没有基类olf Animal 在这种情况下)。

              另一方面,这当然不是访问类成员的优雅和安全的方式。如果您想通过基类实例访问一些公共成员,那么您应该在您的基类中声明这些成员(可能是abstractvirtual),然后在派生类中实现(或覆盖)它们。

              【讨论】:

              • 是的,但这有点违背了目的......只是为了访问东西而低头...... ickypants。
              • 我可能会向 OP 展示如何使用 as.. 安全地进行转换可能不会成功:(
              【解决方案7】:

              你没有很好地定义 Farm 类。这是一个例子:

               public class Animal { }
                  public class Sheep : Animal {
                      public void makeALamb() { }
                  }
              public class Goat: Animal {
                      public void makeAGoat() { }
                  }
                  public class Farm
                  {
                      public Goat myGoat;
                      public Sheep mySheep;
                  }
                  public class MyFarm : Farm {
                      public void MyFarm() {
                          this.mySheep= new Animal();
                          this.mySheep.makeALamb();
                      }
                  }
              

              每只动物都不是山羊,但每只山羊都是动物。

              【讨论】:

                【解决方案8】:

                既然你想使用多态,就把你的代码改成:

                public abstract class Animal 
                {
                    public abstract void makeChild();
                }
                
                public class Sheep : Animal
                {
                    public override void makeChild() 
                    {
                        Console.WriteLine("A lamb is born.");
                    }
                }
                
                public class Cow : Animal
                {
                    public override void makeChild()
                    {
                        Console.WriteLine("A calf is born.");
                    }
                }
                
                public class Farm
                {
                    public Animal myAnimal;
                }
                
                public class SheepFarm : Farm
                {
                    public SheepFarm()
                    {
                        this.myAnimal = new Sheep();
                        this.myAnimal.makeChild();
                    }
                }
                
                public class CowFarm : Farm
                {
                    public CowFarm()
                    {
                        this.myAnimal = new Cow();
                        this.myAnimal.makeChild();
                    }
                }
                

                并且,使用以下“Main()”方法:

                class Program
                {
                    static void Main(string[] args)
                    {
                        Farm sf = new SheepFarm();
                        Farm cf = new CowFarm();
                    }
                }
                

                但是,我应该指出,这不是一个好的用例场景。一个更好、更简单的多态用例是摆脱 Farm 类并使用以下“Main()”方法而不是之前的方法:

                class Program
                {
                    static void Main(string[] args)
                    {
                        Animal[] animals = {
                            new Sheep(),
                            new Cow(),
                            new Sheep(),
                            new Cow(),
                            new Cow()
                        };
                
                        foreach (Animal animal in animals)
                        {
                            animal.makeChild();
                        }
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2014-12-20
                  • 1970-01-01
                  • 2014-03-28
                  • 2018-07-31
                  • 2011-01-18
                  • 1970-01-01
                  • 2017-07-07
                  • 1970-01-01
                  相关资源
                  最近更新 更多