[英]What is the best way to differentiate between derived classes of a base class?
I have base class BaseClass
and derived classes DerivedA
, DerivedB
, and DerivedC
that all inherit BaseClass
. 我有基类
BaseClass
和派生类DerivedA
, DerivedB
和DerivedC
都继承BaseClass
。
I have another class, ExternalClass
with a method that accepts a parameter of type BaseClass
, but is actually passed a derived class. 我有另一个类,
ExternalClass
,其方法接受BaseClass
类型的参数,但实际上传递了派生类。 What is the best way to differentiate between these classes in ExternalClass
if I wanted to perform a different action based on which derived class it received? 如果我想根据收到的派生类执行不同的操作,那么在
ExternalClass
区分这些类的最佳方法是什么?
I was thinking of doing a Select
but I'm not exactly sure how. 我正在考虑做一个
Select
但我不确定如何。
Your design is very likely to be flawed. 你的设计很有可能存在缺陷。 You should consider making the behavior a method of
BaseClass
and override it in each derived class. 您应该考虑将该行为作为
BaseClass
的方法,并在每个派生类中重写它。 You shouldn't check for the actual type of the object. 您不应该检查对象的实际类型。
That is, ExternalClass
should just call a method declared in BaseClass
regardless of the actual type. 也就是说,无论实际类型如何,
ExternalClass
都应该调用在BaseClass
声明的方法。 Since the method is overriden by derived classes, the appropriate implementation will be called. 由于该方法被派生类覆盖,因此将调用适当的实现。
That said, to check if an object is an instance of a type or its derived classes, you can use the is
operator: 也就是说,要检查对象是否是类型的实例或其派生类,您可以使用
is
运算符:
if (obj is DerivedA) // C#
If TypeOf obj Is DerivedA Then ' // VB
If you want to check if the object is an instance of a specific type (and not its derived types): 如果要检查对象是否是特定类型的实例(而不是其派生类型):
if (obj.GetType() == typeof(DerivedA)) // C#
If obj.GetType() Is GetType(DerivedA) Then ' // VB
This is precisely what polymorphism is designed to let you do, frequently riding under the tagline " select
is harmful." 这正是多态性旨在让你做的,经常骑在标语“
select
是有害的”。 A good rule of thumb: you should never have to use a select
statement to differentiate between different types of objects. 一个好的经验法则:您永远不必使用
select
语句来区分不同类型的对象。
Create a method on BaseClass
, even if it's abstract
and does nothing. 在
BaseClass
上创建一个方法,即使它是abstract
并且什么都不做。 This communicates (to humans and to compilers) that all subclasses of BaseClass
need to implement that operation. 这传达(对人类和编译器)
BaseClass
所有子类都需要实现该操作。 Then implement it appropriately in DerivedA
, DerivedB
, and DerivedC
. 然后在
DerivedA
, DerivedB
和DerivedC
适当地实现它。
This way, simply having a variable declared as type BaseClass
entitles you to call that method. 这样,只需将一个声明为
BaseClass
类型的变量授权您调用该方法即可。 It's up to ASP.NET to work out which specific implementation is appropriate based on the type of object you actually end up having. 由ASP.NET根据您实际最终拥有的对象类型确定哪种特定实现是合适的。
Here's a very simple example: 这是一个非常简单的例子:
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();
}
}
Presumably your real-world ExternalClass would be non-static, of course. 当然,大概你的真实世界的ExternalClass是非静态的。
Alternately you can use the following to share behavior: 或者,您可以使用以下内容来共享行为:
public class BaseClass
{
public virtual void SomeAction()
{
Console.WriteLine("Base!");
}
}
public class DerivedA : BaseClass
{
public override void SomeAction()
{
Console.WriteLine("A!");
base.SomeAction();
}
}
While I totally agree with Mehrdad, here's how you can check for the type of an object: 虽然我完全同意Mehrdad,但这里是你如何检查一个对象的类型:
public MyMethod(BaseClass obj)
{
if (obj is DerivedA) { ... }
if (obj is DerivedB) { ... }
}
You do not need to check types to do what you want to do. 您无需检查类型即可执行您想要执行的操作。 You should look at Visitor pattern.
你应该看看访客模式。 You can find all information about it in GoF book or at www.dofactory.com, but let me explain my point:
您可以在GoF书籍或www.dofactory.com上找到有关它的所有信息,但让我解释一下我的观点:
Your external class will implement IVisitor interface that will have methods DoDerivedA(), DoDerivedB and DoDerivedC. 您的外部类将实现具有DoDerivedA(),DoDerivedB和DoDerivedC方法的IVisitor接口。 After that you should add to BaseClass virtual function that will use your external class:
之后你应该添加将使用你的外部类的BaseClass虚函数:
public virtual void DoExternal(IVisitor v){}
DerivedA will override this method like that: DerivedA将覆盖此方法:
v.DoDerivedA();
After that you`ll have something like that in your External: 之后你会在你的外部有类似的东西:
AcceptBaseByExternal(BaseClass derivedInstance)
{
derived.DoExternal(this);
}
This will do anything you want according to the actual class type. 这将根据实际的类类型执行任何操作。 All you need is create a specific method for every derived class.
您所需要的只是为每个派生类创建一个特定的方法。
When I wrote it I also thought that you could create one method in your ExternalClass instead of single method for single derived class and parametrize it with some parameter. 当我编写它时,我还认为您可以在ExternalClass中创建一个方法,而不是单个派生类的单个方法,并使用一些参数对其进行参数化。 Eg implement virtual function in BaseClass that returns enum and every derived should override that enum so that ExternalClass know what code it should execute.
例如,在BaseClass中实现返回枚举的虚函数,每个派生都应覆盖该枚举,以便ExternalClass知道它应该执行什么代码。
IF you're looking to differentiate explicitly between the parent/derived class, IMO, that is an indication to review the design. 如果您希望在父/派生类IMO之间明确区分,则表明要检查设计。 Used correctly, the derived class should be directly substitutable .
正确使用,派生类应该可以直接替换 。
Use a virtual function instead . 请改用虚拟功能。
switch has its place in OOP - where an object can change its state and the current action is based on its present state. switch在OOP中占有一席之地 - 对象可以在其中更改其状态,当前操作基于其当前状态。
Most of the time, switch is misused. 大多数时候,交换机被滥用。 If you ever find you are using switch on a value which remains constant within your object then you should probably be using polymorphism.
如果你发现你正在使用一个在你的对象中保持不变的值的开关那么你应该使用多态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.