2012-05-07 2 views
1

У меня есть базовый класс Person и три производных. На странице редактирования у меня есть раздел с данными общего человека (имя, адрес и т. Д.).Каков наилучший способ проверить, существует ли подкласс определенного типа?

Я также хочу раздел для каждого подкласса. Поэтому, если Person является User Я хочу добавить раздел с конкретными данными пользователя. Если Person также является CardHolder, я хочу показать раздел держателя карты.

Я борюсь за то, как это реализовать. Я имею в виду, чтобы задать UserRepository, если указанным Person является User. Если это так, метод вернет объект User; иначе null. Я планирую сделать это для всех подклассов.

Однако у меня есть это чувство, что это можно сделать лучше, но я не могу найти этот путь.

EDIT:
У меня следующий сценарий. У меня есть обзор с объектами Person (а не с производными!). Когда нажимается строка, я хочу показать страницу сведений. На этой странице у меня есть разные разделы, как описано выше. На этом этапе я хочу знать, является ли «Лицо» также User или «Держателем карты».

Я хотел бы применить полиморфизм, но я не вижу, как ...

+2

Если вы используете логику, основанную на типе объекта, вы делаете это неправильно. – jason

+0

@Jason Как бы вы это реализовали? – Martijn

+1

Я бы воспользовался этим: http://en.wikipedia.org/wiki/Method_overriding – jason

ответ

2

Есть абстрактную функцию на классе Person называется что-то вроде «ReturnValidSectionsForPerson()». В каждом подклассе переопределите эту функцию для возврата «UserData» или «CardHolder» в зависимости от ситуации. Вы можете использовать перечисление для хранения различных типов разделов, чтобы было легче читать и поддерживать.

+0

Thnx, но мне интересно, как это реализовать. У меня есть обзор с объектами Person, затем я нажимаю строку и перехожу на экран подробностей. На экране сведений у меня есть объект Person. На этом этапе я хочу знать, что это за человек больше (человек может быть владельцем карты, но он также может быть пользователем). – Martijn

+1

Думаю, вы смотрите на него назад. Вы не хотите знать, что человек является владельцем карты или является пользователем; вы хотите знать, должен ли человек иметь раздел UserData или CardholderDetails. Моя рекомендация сводится к тому, чтобы «спросить человека». Имея эту функцию в самом классе, вы можете иметь каждый подкласс (или даже экземпляр подкласса в зависимости от требуемой логики) точно указать, какие разделы он требует. – GWLlosa

+0

Но когда я на странице сведений, у меня есть доступ к объекту 'Person'. Когда я вызываю 'ReturnValidSectionsForPerson()' я получу только раздел человека. – Martijn

1

только использовать оператор is. Оператор is используется для проверки совместимости типа времени выполнения объекта с данным типом. Оператор есть используется в выражении вида:

if(pers is user) 
{ 
} 
else if (pers is cardholder) 
{ 
} 
+0

'else if' является уродливым. – Filburt

+0

Этот тип логики является неправильным способом полиморфизма. Как минимум, это кошмар для поддержания. Что произойдет, если у вас новый тип? Или вы получаете большую иерархию разных типов. Yucky. – jason

+0

@Jason - согласен, что я ищу решение, которое имеет дело с универсальным методом ... подождите, если я найду, будет редактировать здесь –

1

typeof (SubClass).IsSubclassOf(typeof (BaseClass)); // возвращает истину

+0

Этот тип логики - неправильный способ полиморфизма. Как минимум, это кошмар для поддержания. Что произойдет, если у вас новый тип? Или вы получаете большую иерархию разных типов. Yucky. – jason

+0

@ Джейсон - укажите свою идею. – JonH

+0

Почему? GWLlosa уже дал прекрасный ответ, который я поддержал. – jason

2

Я думаю, что вы можете использовать is оператор:

if(Person is User) { /* do something */ } 
if(Person is CardHolder) { /* do something more */ } 

Подробнее here.

Как заметил Джейсон, вы, вероятно, хотите сделать что-то другое, как это:

interface class Person 
{ 
    IEnumerable<Section> GetSections(); 
} 

class User : Person 
{ 
    IEnumerable<Section> GetSections() { return new[] { new PersonSection() }; } 
} 

class CardHolder : Person 
{ 
    IEnumerable<Section> GetSections() 
    { 
      return base.GetSections().Concat(new [] {new CardHolderSection() }); 
    } 
} 
+0

@ downvoter, поясните пожалуйста. –

+0

Этот тип логики является неправильным способом полиморфизма. Как минимум, это кошмар для поддержания. Что произойдет, если у вас новый тип? Или вы получаете большую иерархию разных типов. Yucky. – jason

+1

@ Джейсон, я согласен, что вы, вероятно, должны использовать что-то еще для решения проблемы, но это не всегда возможно, а иногда, если вы находитесь в старой базе кода, которая может быть единственным способом перейти на данный момент. Кроме того, остается вопрос: «Каков наилучший способ проверить, является ли подкласс определенного типа?», А использование оператора 'is' - это способ сделать именно это. То, что вы указываете, - это нечто другое. Поэтому, если вы один из них, я думаю, вы сделали это по неправильной причине. –

0

Может быть, я пропускаю момент, но я думаю, вы должны быть в состоянии сделать «это» проверить:

var isUser = myObject is User; 

Смотрите MSDN:

http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.80%29.aspx

EDIT:

Это простое решение и потребует обслуживания, если добавлено больше классов. Для получения более точного ответа обратитесь к другим решениям.

Надеется, что это помогает,

Christian

+0

Этот тип логики является неправильным способом полиморфизма. Как минимум, это кошмар для поддержания. Что произойдет, если у вас новый тип? Или вы получаете большую иерархию разных типов. Yucky. – jason

+1

@Jason - сэкономить время, в заголовке - раздел комментариев. Вы можете обобщить свой комментарий ONCE вместо того, чтобы добавлять один и тот же комментарий несколько раз. Пожалуйста, прочтите FAQ. – JonH

+0

@JonH: Не согласен. Я проигнорировал этот пост. Я всегда оставляю комментарий к сообщению, когда я спускаюсь вниз. – jason

1

Было бы лучше использовать агрегацию вместо наследования. Сделайте свойства Person.UserData и Person.CardholderDetails и покажите/скройте элементы управления в зависимости от того, является ли свойство соответствия требованиям «null» или нет.

+0

Мне нравится этот подход, но тогда мне нужно создать свойства для каждой новой производной, не так ли? И где/как я могу заполнить эти свойства? – Martijn

+0

Да - свойство для каждого раздела, который требуется отредактировать. И заполняйте их, как вы заполняете регулярные свойства ваших подклассов :) –

0

У меня есть следующий сценарий. У меня есть обзор с объектами Person (а не производными!). При щелчке по строке, я хочу показать страницу с информацией о . На этой странице у меня есть разные разделы, как описано выше . На этом этапе я хочу знать, является ли «Лицо» также User или Cardholder.

Вы можете использовать enum. Так что вы можете сделать что-то вроде этого:

[Flags]  
public enum Test 
{ 
    User, 
    CardHolder 
} 

И затем использовать его в своем классе:

public class Person 
{ 
    //... 
    public Test MyTest; 
} 

так, то вы можете использовать его везде, где вы хотите:

Person person = new Person(); 
person.Test1 = (Test.User | Test.CardHolder); 

//... 

if(person.MyTest == Test.User | Test.CardHolder)) 
{ 
    //Do something 
} 

Или просто :

Person person = new Person(); 
person.Test1 = Test.User; 

//... 

if(person.MyTest == Test.User) 
{ 
    //Do something 
} 

if(person.MyTest == Test.CardHolder) 
{ 
    //Do something 
} 
+0

это выполнимо, но я бы рассмотрел использование полиморфизма, как я предлагаю в своем решении. Но хорошо, что вы предоставляете другой ответ. –

+0

Да, спасибо, infact Я поддержал ваш ответ. :) –

+0

@Fuex, а если он и владелец карты, и пользователь? – JonH

2

Хорошо, есть три вещи, которые вы можете сделать в порядке возрастания предпочтений.

1) Используйте «is», чтобы явно проверить класс объекта. Проблема с этим подходом заключается в том, что он хрупкий. Если вы придумаете новые подклассы в будущем, вам нужно будет изменить свое состояние. Это нарушает принцип «открытый/закрытый»: вам не нужно изменять код, который существует для добавления новых функций.

2) Внесите метод «hasDetails» в Person и переопределите его в User. Затем вы проверяете «hasDetails», который затем можете реализовать в любом классе, который реализует этот интерфейс. Это предпочтительнее, потому что он позволяет вам добавлять новый код без изменения существующего кода, но он негибкий, поскольку предполагает, что все детали одинаковы.

3) «Скажите, не спрашивайте». Не спрашивайте объект для информации о себе и делайте что-то на основе результата. Вместо этого скажите объекту, чтобы он сам выполнял операцию. Это позволяет объекту решать, когда это делать и как это сделать.

Использование # 3 предпочтительнее в большинстве случаев, но есть ситуации, когда у вас действительно нет выбора, кроме как пойти с № 2 (например, упаковка или расслоение требует, чтобы операция, которую вы хотите выполнить, не могла выполняться Лицом объект) или даже с # 1 (например, вы не имеете доступа к исходному коду класса Person или не можете добавлять к нему методы).

+0

Thans for answer, но я не могу использовать ни один из них. Проблема в том, что у меня есть обзор только с объектами «Person» (они извлекаются из «PersonRepository»). Поэтому, когда я на странице сведений, у меня есть только объект Person. Когда я использую оператор 'is', он всегда будет возвращать false, потому что другие типы никогда не загружаются. – Martijn

+0

Можете ли вы объяснить свою иерархию классов, чтобы я мог лучше понять? Являются ли подклассы Person и CardHolder для Person? Если это так, я думаю, проблема заключается в том, что ваш PersonRepository возвращает только экземпляры Superclass Person вместо соответствующего подкласса. Опять же, возможно, я просто не понимаю вопроса. –

+0

Да, это правильно, в обзоре показаны только объекты Person.Он ничего не может показать, потому что «Лицо» также может быть «Пользователем», а также «Держателем карты» – Martijn

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