我有一种情况,我有一个抽象的基类对象用作占位符来实例化派生对象...例如......
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”之前。
答案 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);
}
}
}
}
组合似乎是一个更好的选择,它缩短了继承链并在派生类中保留了特定于水果的实现。单一责任原则和所有这些。