可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have base class BaseClass
and derived classes DerivedA
, DerivedB
, and DerivedC
that all inherit BaseClass
.
I have another class, ExternalClass
with a method that accepts a parameter of type BaseClass
, but is actually passed a derived class. 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?
I was thinking of doing a Select
but I'm not exactly sure how.
回答1:
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. 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. 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:
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
回答2:
This is precisely what polymorphism is designed to let you do, frequently riding under the tagline "select
is harmful." A good rule of thumb: you should never have to use a select
statement to differentiate between different types of objects.
Create a method on BaseClass
, even if it's abstract
and does nothing. This communicates (to humans and to compilers) that all subclasses of BaseClass
need to implement that operation. Then implement it appropriately in DerivedA
, DerivedB
, and DerivedC
.
This way, simply having a variable declared as type BaseClass
entitles you to call that method. 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.
回答3:
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.
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();
}
}
回答4:
While I totally agree with Mehrdad, here's how you can check for the type of an object:
public MyMethod(BaseClass obj)
{
if (obj is DerivedA) { ... }
if (obj is DerivedB) { ... }
}
回答5:
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:
Your external class will implement IVisitor interface that will have methods DoDerivedA(), DoDerivedB and DoDerivedC. After that you should add to BaseClass virtual function that will use your external class:
public virtual void DoExternal(IVisitor v){}
DerivedA will override this method like that:
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. E.g. implement virtual function in BaseClass that returns enum and every derived should override that enum so that ExternalClass know what code it should execute.
回答6:
IF you're looking to differentiate explicitly between the parent/derived class, IMO, that is an indication to review the design. Used correctly, the derived class should be directly substitutable.
Use a virtual function instead .
回答7:
switch has its place in OOP - where an object can change its state and the current action is based on its present state.
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.