Как лучше всего провести различие между производными классами базового класса? - PullRequest
2 голосов
/ 29 августа 2009

У меня есть базовый класс BaseClass и производные классы DerivedA, DerivedB и DerivedC, которые все наследуют BaseClass.

У меня есть другой класс, ExternalClass с методом, который принимает параметр типа BaseClass, но на самом деле передается производный класс. Как лучше всего провести различие между этими классами в ExternalClass, если бы я хотел выполнить другое действие в зависимости от того, какой производный класс он получил?

Я думал о Select, но я не совсем уверен, как.

Ответы [ 7 ]

18 голосов
/ 29 августа 2009

Ваш дизайн, скорее всего, будет ошибочным. Вам следует подумать о том, чтобы сделать поведение методом 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
2 голосов
/ 29 августа 2009

Вот очень простой пример:

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();
    }
}

Предположительно, ваш реальный внешний класс ExternalClass будет, конечно, нестатичным.

В качестве альтернативы вы можете использовать следующее для обмена поведением:

public class BaseClass
{
    public virtual void SomeAction()
    {
        Console.WriteLine("Base!");
    }
}

public class DerivedA : BaseClass
{
    public override void SomeAction()
    {
        Console.WriteLine("A!");
        base.SomeAction();
    }
}
2 голосов
/ 29 августа 2009

Это именно то, что позволяет вам сделать полиморфизм, часто езда под лозунгом «select вредна». Хорошее практическое правило: вам никогда не придется использовать оператор select, чтобы различать различные типы объектов.

Создайте метод на BaseClass, даже если он abstract и ничего не делает. Это сообщает (людям и компиляторам), что все подклассы BaseClass должны реализовать эту операцию. Затем примените его соответствующим образом в DerivedA, DerivedB и DerivedC.

Таким образом, просто объявив переменную типа BaseClass, вы можете вызывать этот метод. Именно ASP.NET должен определить, какая конкретная реализация подходит в зависимости от типа объекта, который у вас действительно есть.

0 голосов
/ 03 сентября 2009

переключатель имеет свое место в ООП - где объект может изменить свое состояние, а текущее действие основано на его текущем состоянии.

В большинстве случаев переключатель используется не по назначению. Если вы когда-нибудь обнаружите, что используете переключение на значение, которое остается постоянным внутри вашего объекта, то вам, вероятно, следует использовать полиморфизм.

0 голосов
/ 01 сентября 2009

ЕСЛИ вы хотите провести четкое различие между родительским / производным классом, IMO, который является показателем для проверки проекта. При правильном использовании производный класс должен быть заменяемым .

.

Вместо этого используйте виртуальную функцию.

0 голосов
/ 29 августа 2009

Вам не нужно проверять типы, чтобы делать то, что вы хотите. Вы должны посмотреть на шаблон посетителя. Вы можете найти всю информацию об этом в книге GoF или на www.dofactory.com, но позвольте мне объяснить мою точку зрения:

Ваш внешний класс будет реализовывать интерфейс IVisitor, который будет иметь методы DoDerivedA (), DoDerivedB и DoDerivedC. После этого вам нужно добавить в BaseClass виртуальную функцию, которая будет использовать ваш внешний класс:

public virtual void DoExternal(IVisitor v){}

DerivedA переопределит этот метод следующим образом:

v.DoDerivedA();

После этого у вас будет что-то подобное в вашем Внешнем:

AcceptBaseByExternal(BaseClass derivedInstance)
{
  derived.DoExternal(this);
}

Это будет делать все, что вы хотите в соответствии с фактическим типом класса. Все, что вам нужно, это создать специальный метод для каждого производного класса.

Когда я писал это, я также думал, что вы можете создать один метод в вашем ExternalClass вместо одного метода для одного производного класса и параметризовать его с помощью какого-либо параметра. Например. реализовать виртуальную функцию в BaseClass, которая возвращает перечисление, и каждый производный должен переопределить это перечисление, чтобы ExternalClass знал, какой код он должен выполнять.

0 голосов
/ 29 августа 2009

Хотя я полностью согласен с Мехрдадом, вот как вы можете проверить тип объекта:

public MyMethod(BaseClass obj)
{
  if (obj is DerivedA) { ... }
  if (obj is DerivedB) { ... }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...