简体   繁体   English

区分基类的派生类的最佳方法是什么?

[英]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和派生类DerivedADerivedBDerivedC都继承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 . 然后在DerivedADerivedBDerivedC适当地实现它。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM