Возвращая интерфейс, но бетон может иметь свойства не на интерфейсе, могу ли я получить их с помощью приведения? - PullRequest
4 голосов
/ 28 января 2012

У меня такое ощущение, что я неправильно использую интерфейс.Я знаю, что интерфейс - это контракт, которому должен соответствовать конкретный класс.

Поэтому я объясню проблему, которую пытаюсь решить, и, возможно, кто-то может указать мне правильное направление.

Я создаю приложение, которое возвращает страницу для любого запроса, у меня есть три типа страниц, Cms, Product и Category.

Все три должны реализовать следующий интерфейс:

public interface IPage
    {
        PageType PageType { get; set; }
        PageContent Content { get; set; }
        Meta Meta { get; set; }
    }

Эти свойства запрашиваются независимо от типа страницы.

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

public class CategoryPage : IPage
    {
        public PageType PageType { get; set; }
        public PageContent Content { get; set; }
        public Meta Meta { get; set; }

        public List<Product> Products { get; set; }
    }

На данный момент у меня естьслужба страниц, которая будет возвращать страницу для запрошенного URL.

На основе PageType она знает, какой тип страницы должен возвращаться.

Проблема заключается в том, что pageService возвращает IPage, чтобы он могвернуть любой из типов страниц.

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

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

Спасибо

Обновление

Я согласился на приведение.

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

Или, может быть, то, что я пытаюсь сделать здесь, просто неправильно, и янужно принять другой подход.Я думаю, что буду настаивать на том, что у меня есть сейчас, но продолжаю думать об этом.

Обновление 2

Я изменил способ, которым я делаю это, поэтому у меня нет необходимости в приведении, у меня есть перечисление PageType, которое я использую для определения типастраницы, с которой ведется работа.

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

Ответы [ 4 ]

2 голосов
/ 28 января 2012

Вы всегда можете проверить, относится ли объект, на который вы ссылаетесь, к определенному типу, используя ключевое слово ;

if(obj is Class1) {

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

1 голос
/ 28 января 2012

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

Если вы возвращаете страницу, на самом деле нет никаких оснований знать, что это за страница. Я бы добавил Render метод к интерфейсу IPage, так что все, что нужно сделать получателю, это вызвать Render(), а остальная страница обработает все остальное.

0 голосов
/ 28 января 2012

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

В некотором смысле, это не элегантно иметь коллекцию объектов, которые имеют различные способности (или фабричный метод, который будет возвращать различные способности) в тех случаях, когда может быть необходимо использовать способности, которые существуют в одних объектах, но не в других. Конечно, можно сказать что-то вроде

  IInterfaceThatMayOrMayNotBePresent foo = bar as IInterfaceThatMayOrmayNotBePresent;
  if (foo != null)
    foo.MethodOfThatInterface();

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

Например, предположим, что некоторые типы объектов хотят получать уведомления, если происходит «Wowzo»; другие типы не заботятся. Кроме того, ожидается наличие списков, содержащих объекты обоих типов, и потребуется уведомить, уведомить все элементы, которые заботятся. Можно использовать вышеупомянутый шаблон проверки типов для уведомления только тех элементов, которые в этом нуждаются, но может быть более эффективный подход: можно определить два интерфейса: IAcceptWowzoNotifications и IActOnWowzoNotifications, причем последний наследует первый. Ожидается, что классы, которые реализуют первое, но не второе, будут реализовывать уведомления Wowzo с пустыми методами. Если каждый элемент в списке реализует IAcceptWowzoNotifications, независимо от того, делает ли он что-либо с таким уведомлением, быстрее будет просто уведомить всех в списке, чем проверять, какие элементы требуют уведомления.

Обратите внимание, что этот подход не совсем без затрат. Прежде всего, поскольку нет интерфейсов, предлагающих реализации методов по умолчанию, каждый тип, который реализует IAcceptWowzoNotifications, должен будет определять методы-заглушки. Кроме того, если единственная причина, по которой элемент будет добавлен в список, состоит в том, чтобы отправлять ему уведомления Wowzo, и если уведомление всех в списке будет более частым явлением, чем добавление элементов в список, было бы лучше проверить, items реализует IActOnWowzoNotifications перед добавлением их в список, чем для слепого добавления элементов в список, которые могут быть, а могут и не быть там.

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

0 голосов
/ 28 января 2012

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

        IPage page;
        if (page is CategoryPage)
        {
           // use type here
        }

        CategoryPage categoryPage = page as CategoryPage;
        if (categoryPage != null)
        {
          // use type here
        }
...