C#将基础对象实例化为派生对象

时间:2016-07-30 01:45:25

标签: c# inheritance

我有一种情况,我有一个抽象的基类对象用作占位符来实例化派生对象...例如......

public abstract class Fruit(){ //stuff}

public class Banana() : Fruit(){ //stuff }

public class Apple() : Fruit(){ //stuff }

public class FruitSalad() 
{
 Fruit SomeKindOfFruit;
 public DoStuff(Fruit frt)
 { 
   SomeKindOfFruit = new ?????
 }
}

所以,这个功能将接受一个水果...该程序不知道什么样的水果......可能是一个苹果...可能是一个香蕉...可能是一个新西兰...但我需要它输入frt,然后告诉SomeKindOfFruit,“嘿.. frt是Apple,所以你现在是Apple”。

我知道SomeKindOfFruit =新Apple();工作...但我不想要做的是必须硬编码一堆if / then语句或一个开关来评估类型,然后显式声明每个可能的派生类......以及那些派生类的派生类class ...和衍生类的派生类... ad nauseum ...特别是因为即使这样做我也必须拉动类型甚至评估它,只是能够说出来会容易得多,“看到这个派生的东西?不管是什么东西,你现在都是那种东西”。只需要一段代码,这样我就可以创建尽可能多的派生类,它只会继续工作;我不必反复添加更多评估。

[编辑]

这就是我的想法......我最初试图做一个简单的等式......它会抛出一个空的引用异常。好吧,所以我实际上做的与水果无关,但这是描述问题最简单的方法而不会迷失在杂草中。实际程序正在做的是我有2个类......好吧,一个运行GUI组件的类和一组类(基类+派生类),这些类是在引擎盖下操作的所有数据类型网络。在每个类中,我创建了一个对象,理论上应该引用它们。顺序是从存储的SQL数据创建数据类。一旦创建了所有数据,我在数据类中有一个方法,它创建将在GUI上显示它的图形类。部分原因是数据类应该为图形类提供一个自我反射,这样两个类都可以引用另一个,信息可以双向...我可以通过图形组件将信息发送到其相关数据中class和data类可以从网上获取信息并以图形方式显示

public abstract class baseData() {
public graphicClass GraphicRepresentation;

     public baseData(stuff){
     //Sets all the relevant data
     }

     public void Activate(){
     GraphicRepresentation = new graphicClass();
     //Sets all the relevant components in the class
     GraphicRepresentation.DataReference = this;
     }`
  }

以上引发了空引用异常。我能想到的唯一的事情是DataReference,它是一个baseData对象,需要先实例化,然后才能将“this”分配给它,但是我无法实例化一个抽象类,所以我必须能够实例化它因为任何派生类型“this”在我可以使它等于“this”之前。

3 个答案:

答案 0 :(得分:2)

你可以使你的方法通用:

public class FruitSalad() 
{
    Fruit SomeKindOfFruit;

    public DoStuff<TFruit>(TFruit frt)
        where TFruit : Fruit, new()
    {
        SomeeKindOfFruit = new TFruit();
    }

答案 1 :(得分:1)

我认为你错过了这一点。

首先,您的DoStuff方法建议temporary field code smell。类字段应在构造函数中初始化,而不是在方法中初始化。如果我要实现FruitSalad类,我可能会写它:

public class FruitSalad
{
    private readonly Fruit _fruit;

    public FruitSalad(Fruit fruit)
    {
        _fruit = fruit;
    }

    public DoStuff()
    {
        // Act on the _fruit field
    }
}

其次,Fruit传递给DoStuff的构造函数/ FruitSalad方法的实际运行时类型是什么并不重要,只要它是从{{1}派生的}}。这是 polymorphism

例如,如果Fruit中有abstract方法CutToPieces,则为:

Fruit

public abstract class Fruit { public abstract void CutToPieces(); } Apple的实施方式如下:

Banana

您的public class Apple : Fruit { public override void CutToPieces() { Console.WriteLine("Apple being diced"); } } public class Banana : Fruit { public override void CutToPieces() { Console.WriteLine("Banana being cut to small pieces"); } } 仍然可以在不知道传入的FruitSalad实例的实际运行时类型的情况下准备好:

Fruit

答案 2 :(得分:0)

CLR已经有了这方面的工具:

void GetFruitType(Fruit fruit)
{
    Type t = fruit.GetType();
    if (t.Equals(typeof(Apple))) HandleApple();
}

但是,如果您想避免处理猜测并切换所有类型,则应使用合成而不是继承:

interface IFruit
{
    void CutFruit();
}


class Apple : IFruit
{
    public void IFruit.CutFruit()
    {
        // Implementation for apple
        // For fruits that do not support cutting, you still need to
        // implement the interface, but you can throw a NotSupportedException
        // and then catch the exception in the FruitSalad class
    }
}

class Grape : IFruit
{
    public void IFruit.CutFruit()
    {
        throw new NotSupportedException("You don't cut grapes...");
    }   
}

class FruitSalad
{
    IFruit[] _fruits = null; // Initialize in constructor or through property

    void CutFruits()
    {
        foreach (IFruit fruit in _fruits)
        {
            try
            {
                fruit.CutFruit();
            }
            catch (NotSupportedException ex)
            {
                Debug.Print(ex.Message);
            }
        }
    }   
}

组合似乎是一个更好的选择,它缩短了继承链并在派生类中保留了特定于水果的实现。单一责任原则和所有这些。