2009-08-29 6 views
2

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

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

Я думал о том, чтобы делать Select, но я точно не знаю, как это сделать.

ответ

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 
+11

+1 солидный совет. Если вы когда-либо обнаруживаете, что используете тип класса в дереве наследования, вы, вероятно, делаете что-то неправильно. – womp

+3

благодарит за то, что дал мне понять, что я ошибаюсь. это полезно. – Jason

+0

@womp - что делать, если я в UserControl, который имеет «BaseClass» в качестве члена, и должен инстанцировать его только с помощью идентификатора, переданного ему в качестве параметра. Как узнать, какой производный класс был создан для создания экземпляра, если я также не передам что-то вроде перечисленного значения, чтобы сообщить ему, какой из них? – Jason

2

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

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

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

0

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

public MyMethod(BaseClass obj) 
{ 
    if (obj is DerivedA) { ... } 
    if (obj is DerivedB) { ... } 
} 
+0

Чтобы быть разборчивым, это проверяет, может ли объект быть преобразован в DerivedA, а не в DerivedA. Если у DerivedA был дочерний элемент DerivedAPrime, он прошел бы первый тест, который может или не может быть хорошим. –

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

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

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

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

public class DerivedA : BaseClass 
{ 
    public override void SomeAction() 
    { 
     Console.WriteLine("A!"); 
     base.SomeAction(); 
    } 
} 
0

Вам не нужно, чтобы проверить типы, чтобы делать то, что вы хотите сделать. Вы должны посмотреть на шаблон посетителя. Вы можете найти всю информацию об этом в книге 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, которая возвращает enum, и каждый производный должен переопределить это перечисление, чтобы ExternalClass знал, какой код он должен выполнить.

0

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

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

0

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

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

Смежные вопросы