我有基类BaseClass
以及所有继承DerivedA
的派生类DerivedB
,DerivedC
和BaseClass
。
我有另一个类ExternalClass
,其方法接受类型为BaseClass
的参数,但实际上是传递了派生类。如果我想根据收到的派生类执行不同的操作,那么在ExternalClass
中区分这些类的最佳方法是什么?
我在考虑做Select
,但我不确定如何。
答案 0 :(得分:18)
您的设计很可能存在缺陷。您应该考虑将行为设为BaseClass
的方法,并在每个派生类中覆盖它。您不应该检查对象的实际类型。
也就是说,ExternalClass
应该只调用BaseClass
中声明的方法,而不管实际类型如何。由于该方法被派生类覆盖,因此将调用适当的实现。
也就是说,要检查对象是否是类型的实例或其派生类,可以使用is
运算符:
if (obj is DerivedA) // C#
If TypeOf obj Is DerivedA Then ' // VB
如果要检查对象是否是特定类型的实例(而不是其派生类型):
if (obj.GetType() == typeof(DerivedA)) // C#
If obj.GetType() Is GetType(DerivedA) Then ' // VB
答案 1 :(得分:2)
这正是多态性旨在让你做的事情,经常骑在标语“select
是有害的”。一个好的经验法则:您永远不必使用select
语句来区分不同类型的对象。
在BaseClass
上创建一个方法,即使它是abstract
并且什么都不做。这传达(对人类和编译器)BaseClass
的所有子类都需要实现该操作。然后在DerivedA
,DerivedB
和DerivedC
中正确实施。
这样,只需将变量声明为类型BaseClass
即可授权您调用该方法。由ASP.NET根据您实际最终拥有的对象类型确定哪种特定实现是合适的。
答案 2 :(得分:2)
这是一个非常简单的例子:
using System;
public abstract class BaseClass
{
public abstract void SomeAction();
}
public class DerivedA : BaseClass
{
public override void SomeAction()
{
Console.WriteLine("A!");
}
}
public class DerivedB : BaseClass
{
public override void SomeAction()
{
Console.WriteLine("B!");
}
}
public class ExternalClass
{
public static void Main()
{
DoIt(new DerivedA());
DoIt(new DerivedB());
Console.ReadLine();
}
public static void DoIt(BaseClass baseClass)
{
baseClass.SomeAction();
}
}
当然,大概你的真实外部类是非静态的。
或者,您可以使用以下内容来共享行为:
public class BaseClass
{
public virtual void SomeAction()
{
Console.WriteLine("Base!");
}
}
public class DerivedA : BaseClass
{
public override void SomeAction()
{
Console.WriteLine("A!");
base.SomeAction();
}
}
答案 3 :(得分:0)
虽然我完全赞同Mehrdad,但这里是你如何检查对象的类型:
public MyMethod(BaseClass obj)
{
if (obj is DerivedA) { ... }
if (obj is DerivedB) { ... }
}
答案 4 :(得分:0)
您无需检查类型即可执行您想要执行的操作。你应该看看访客模式。 您可以在GoF书籍或www.dofactory.com上找到有关它的所有信息,但让我解释一下我的观点:
您的外部类将实现具有DoDerivedA(),DoDerivedB和DoDerivedC方法的IVisitor接口。之后,您应该添加将使用外部类的BaseClass虚函数:
public virtual void DoExternal(IVisitor v){}
DerivedA将覆盖此方法:
v.DoDerivedA();
之后你会在你的外部有类似的东西:
AcceptBaseByExternal(BaseClass derivedInstance)
{
derived.DoExternal(this);
}
根据实际的班级类型,这将做任何你想做的事情。您所需要的只是为每个派生类创建一个特定的方法。
当我编写它时,我还认为您可以在ExternalClass中创建一个方法,而不是单个派生类的单个方法,并使用一些参数对其进行参数化。例如。在BaseClass中实现返回枚举的虚函数,每个派生都应该重写该枚举,以便ExternalClass知道它应该执行什么代码。
答案 5 :(得分:0)
如果您希望明确区分父/派生类IMO,那就是审查设计的指示。如果使用得当,派生类应该直接可替代。
改为使用虚拟功能。
答案 6 :(得分:0)
switch在OOP中占有一席之地 - 对象可以在其中更改其状态,当前操作基于其当前状态。
大多数情况下,交换机被滥用。如果你发现你正在使用一个在你的对象中保持不变的值的开关那么你可能应该使用多态。