【发布时间】:2015-10-03 12:47:30
【问题描述】:
我花了几个小时试图找到一种方法来实现这一点,但到目前为止我还没有找到一个好的解决方案,所以我希望有人可以帮助我指出正确的方向。
我目前有一个 C# Winforms 项目,该项目有一个带有多个子类的抽象基类。大多数方法是相同的,但每个子类都有一些特定的附加方法。
我希望能够声明一次使用的类的类型并将该类型传递给我的所有其他方法,而不必通过“如果 Class Type=A Do This Else If Class Type=”来手动检查任何地方的类型B 这样做,等等”。
问题是我需要传递基类或接口来完成这个。但是,这样做意味着我无法再访问特定于子类的属性或方法,并且我不知道如何修复/解决此问题。
这是我正在尝试做的一个简化示例:
接口和类结构
public interface IAnimal
{
string NameOfAnimal { get; set; }
void Eat();
}
public abstract class Animal : IAnimal
{
public abstract string NameOfAnimal { get; set; }
public abstract void Eat();
}
public class Bird : Animal
{
public Bird()
{
NameOfAnimal = "Bob the Bird";
NumberOfFeathers = 100;
}
// Interface members
public override string NameOfAnimal { get; set; }
public override void Eat()
{
System.Windows.Forms.MessageBox.Show("Eating like a Bird");
}
// Bird specific properties and methods
public int NumberOfFeathers { get; protected set; }
public string SomeOtherBirdSpecificProperty { get; protected set; }
public void Fly()
{
// Fly like a bird
}
}
public class Fish : Animal
{
public Fish()
{
NameOfAnimal = "Jill the Fish";
DoesFishHaveSharpTeeth = true;
}
// Interface members
public override string NameOfAnimal { get; set; }
public override void Eat()
{
System.Windows.Forms.MessageBox.Show("Eating like a Fish");
}
// Fish specific properties
public bool DoesFishHaveSharpTeeth { get; protected set; }
public string SomeOtherFishSpecificProperty { get; protected set; }
}
主窗体代码
private void button1_Click(object sender, EventArgs e)
{
IAnimal myCustomAnimal = null;
string animalTheUserSelected = "Bird";
// Only want to manually specify this once
switch (animalTheUserSelected)
{
case "Bird":
myCustomAnimal = new Bird();
break;
case "Fish":
myCustomAnimal = new Fish();
break;
default:
break;
}
DoSomethingWithACustomAnimal(myCustomAnimal);
}
private void DoSomethingWithACustomAnimal(IAnimal myAnimal)
{
// This works fine
MessageBox.Show(myAnimal.NameOfAnimal);
myAnimal.Eat();
// This doesn't work
MessageBox.Show(myAnimal.NumberOfFeathers);
myAnimal.Fly();
}
我明白为什么我在主表单代码中遇到这个问题...编译器还不知道传递给它的是哪种类型的动物,所以它不知道要显示什么。但是,我不知道该怎么做才能解决这个问题。
我试过了:
将所有动物特有的属性放在界面中。这可行,但违反了几个 OOP 原则。鱼没有羽毛等,因此这些特定属性不属于那里。
通过类似“If Type=Fish do abc Else If Type=Bird do def”之类的方式手动检查各处的类型。这也有效,但违反了 DRY 原则,因为我到处都在重复自己。还有很多使用动物的方法,这将是未来维护的噩梦。
将 IAnimal 显式转换为特定动物,例如 ((Bird)myCustomAnimal).NumberOfFeathers。这也有效,但我不知道在编译时使用什么强制转换。在用户在运行时选择动物之前,我们不会知道这一点。
所以我只是想知道如何解决这个问题?
更具体地说,我想知道如何重新设计上述代码,以便两者兼得:
A) 只显式声明一种动物类型并在任何地方传递该类型(无需在每个方法中进行大量手动检查以查看它是什么类型)
还有
B) 不知何故,我仍然可以在需要时手动访问特定于动物的属性,例如 someBird.NumberOfFeathers。
有什么想法吗?
【问题讨论】:
-
您确实需要考虑您的结构实际上应该是什么。当您遇到此类问题时,不妨坐下来思考一下基本属性是什么,以及如何将它们组合到一个或多个界面中。