2010-10-14 4 views
3

Опять же, я действительно надеюсь, что это не вопрос мнения; Я пытаюсь узнать, какой из них лучше всего определить тип объекта, принадлежащего определенной иерархии на C#. У меня есть два пути для разработки моего приложения:Определение типа объекта

1 - использовать свойство в базовом классе:

public abstract class Parent 
{ 
    public abstract TypeOfObject TypeOfObject { get; } 
} 

public class Child1 : Parent 
{ 
    public override TypeOfObject TypeOfObject { get { return TypeOfObject.Child1 } } 

    // ... 
} 

public class Child2 : Parent 
{ 
    public override TypeOfObject TypeOfObject { get { return TypeOfObject.Child2 } } 

    // ... 
} 

public enum TypeOfObject 
{ 
    Child1, 
    Child2 
} 

public static void Main() 
{ 
    Parent p = new Child1(); 

    switch (p.TypeOfObject) 
    { 
     case TypeOfObject.Child1: _doSomethingWithChild1(p);break; 
     case TypeOfObject.Child2: _doSomethingWithChild2(p);break; 
    } 
} 

2 - Используйте это оператор

public abstract class Parent 
{ 
    // ... 
} 

public class Child1 
{ 
    // ... 
} 


public class Child2 : Parent 
{  
    // ... 
} 

public enum TypeOfObject 
{ 
    Child1, 
    Child2 
} 

public static void Main() 
{ 
    Parent p = new Child1(); 

    if (p is Child1) _doSomethingWithChild1(p); 
    if (p is Child2) _doSomethingWithChild2(p); 
} 

Каковы последствия каждой альтернативы? Я думаю, что 2 имеет более высокий рейтинг производительности, поскольку он опирается на метаданные, но 1 кажется менее элегантным. Кроме того, я научился делать это 1 путь в C++ ... Я не уверен, что это необходимо сделать с C#.

EDIT 1:

Я добавил переопределения ключевое слово в коде выше.

EDIT 2:

извини, я, наверное, не сделал себе ясно. Я проиллюстрирую это лучше:

Например, у меня есть WPF Panel объект, который имеет Children свойство, которое возвращает мне UIElement с. Мне нужно знать, к какому типу должен действовать определенный элемент ... в моем конкретном случае пользователь рисует график на экране, поэтому мне нужно знать, сколько узлов и сколько соединений выполняется для хранения затем в базе данных. Я не могу, к сожалению, использовать для этого полиморфизм, верно? Как узнать, следует ли добавить строку в таблицу узлов или таблицу соединений?

+10

Это обычная ошибка дизайна OO. Вам это не нужно. Пожалуйста, прочитайте «полиморфизм», а затем закройте вопрос. –

+0

Есть много примеров первого пути в .NET Framework, например XmlDocument/XmlElement/..., XDocument/XElement/..., LambdaExpression/UnaryExpression/... – dtb

+0

@ S.Lott: +1 :) (blah) – leppie

ответ

0

Примеры использования неверны (как говорят другие - используйте полиморфизм), но может быть разумным спросить, какой тип объекта.

я задал аналогичный вопрос для C++ Testing a c++ class for features

Что касается разницы между # 1 и # 2. Оба требуют метаданные. В случае 1 вы делаете это, в случае 2 вы все равно используете метаданные, сделанные CLR. CLR, вероятно, лучше в этом, чем вы, и его платит за это в любом случае

Как всегда - если вы хотите узнать, что быстрее, ответы просты - измерьте и посмотрите. Я сомневаюсь, что существует измеримая разница

+0

«может быть разумным спросить, какой тип объекта». Просьба привести пример того, когда это на самом деле «разумно», что не связано с довольно слабым полиморфизмом. К сожалению, ** все ** примеры идентификации типа времени выполнения, которые я когда-либо видел, - это все плохие ошибки полиморфизма. Просьба пояснить на примере. –

+0

http://stackoverflow.com/questions/3336859/testing-a-c-class-for-features – pm100

+0

@ pm100: Как это еще не один пример плохого полиморфизма? Это похоже на то, что должно было быть простым полиморфизмом. Что я упустил? –

4

Первый вариант не является обязательным. если вы посмотрите на Object (база для ВСЕХ объектов на C#), вы найдете член GetType().

В нашем производственном коде, мы часто используем метод 2, в основном для «вниз литья», то есть, отбрасывая мой базовый класс для класса, который является производным от указанного базового класса ...

if (myObject is Type1) dosomething(); 
if (myObject is Type2) dosomethingelse(); 

мы также используем as оператор ....

Type1 object1 = someotherobject as type1; 
if (object1 != null) dosomething(); 

Хорошая вещь об этом, то, что вы не получите исключения, как если бы вы пытались что-то вроде этого:

((TypeFoo)object1).bar(); // if object 1 is NOT of TypeFoo you get an exception 
+0

Вы имели в виду 'GetType' вместо' TypeOf'? – Gabe

+1

Полиморфизм должен сделать что-то * разное * происходить на основе того, является ли 'myObject' типом' Type1' по сравнению с 'Type2' без явной проверки. Если вы работаете на 'myObject' и вам нужно различать его конкретный тип, это означает, что вы неправильно связаны с ним и должны быть рефакторированы. – FMM

+0

в любом случае, вы должны использовать полиморфизм, если можете, однако, когда-нибудь у вас нет этой опции. например, LINQ дает мне IEnumerable, но если это * действительно * Список чего-то, как я могу знать, что если я его не тестирую? –

10

Вы делаете это неправильно ™. Когда-либо слышали о полиморфизме (более поздняя/динамическая привязка, если быть более точным)? Родитель должен иметь абстрактный метод, такой как doSomething(), который должен быть реализован детьми, независимо от того, что было в _doSomethingWithChild1, должно быть в Child1.doSomething и т. Д. Это то, что OO все - ну, не все, но большая часть - о! Часто задаваемые вопросы по C++ утверждают, что C++ не будет объектно ориентирован без virtual.Не только легче или меньше подвержено ошибкам, чтобы добавить другого ребенка (вы просто определяете новый подкласс и метод, не нужно возиться с переключателями или ifs) и, скорее всего, самый быстрый способ (каждый JIT стоит своей соли, использует polymorphic inline caching), это также идиоматично и менее вероятно, чтобы вы поняли, что это «WTF» stare;)

+0

Это фактически то же самое, что и оператор switch. Если вы «переключаетесь» на тип времени выполнения, я согласен, что вы делаете это неправильно (TM). Оглянитесь вокруг рефакторинга операторов коммутатора на полиморфизм. – FMM

+0

Я отредактировал вопрос, чтобы получить более ясный пример. Объекты могут быть полиморфными, но будут моменты, когда мне нужно знать их точный тип. –

+0

@Bruno: Как именно этот пример не работает с полиморфизмом? Если бы вы вставляли вещи в базу данных в зависимости от типа, просто делайте объекты (полиморфно) помещены этой информацией в db? – delnan

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