Проблема с интерфейсами, наследование и полиморфизм - PullRequest
2 голосов
/ 15 сентября 2011

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

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

public interface IMyModel
{ ... }

public class MyModelA : ModelBase, IMyModels
{ ... }

public class MyModelB : ModelBase, IMyModels
{ ... }

public class MyModelC : ModelBase, IMyModels
{ ... }

Пока все хорошо и прекрасно.

У меня есть базовый класс ViewModel, который принимает модель в качестве конструктора:

public abstract class MyViewModelBase
{
    public MyViewModelBase(ModelBase Model)
    this.model = Model;
}

Теперь, где я пойман; Я хочу иметь конкретный класс ViewModel, который может принимать любой из трех классов Model выше:

public class MyViewModel : MyViewModelBase
{
    MyViewModel(IMyModel Model) : base (Model)   // <- Invalid Polymorphism!
    {
        // More here
    }
}

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

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

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

public interface IMyModel : MyModelBase
{ ... }

Есть ли лучший способ сделать это?

Пояснение:

Я, вероятно, упрощенно назвал здесь. У меня есть другие Модели и ViewModel, использующие базовые классы, но не реализующие интерфейс.

public class MyOtherModel : ModelBase  // But not IMyModel!
{ ... }

public class MyOtherViewModel : MyViewModelBase
{
    MyOtherViewModel(MyOtherModel Model) : base(Model)  // This works
    { ... }
}

Ответы [ 5 ]

2 голосов
/ 15 сентября 2011

Вы можете заставить ваш базовый класс реализовывать интерфейс, а затем наследовать ваши классы реализации от базового класса, помечая базовый класс и методы как абстрактный (MustInherit / MustOverride на языке VB).Это даст вам ваш полиморфизм и гарантирует интерфейс.

2 голосов
/ 15 сентября 2011

вы можете использовать общие ограничения:

public class MyViewModel<T> : MyViewModelBase where T : IMyModel , ModelBase
{
    MyViewModel(T model) : base (model)   // T inherits ModelBase and implements IMyModel , so it is legal
    {
        // More here
    }
}
1 голос
/ 15 сентября 2011

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

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

0 голосов
/ 15 сентября 2011

Насколько я понимаю

  • Модели глупы Контейнеры данных
  • Интерфейсы описывают поведение и функциональность, а не данные.

Так зачем же ставить интерфейсы намодели вообще?

@ Yochai: Хорошая точка зрения, использование Generics - сохраняет код, но вы должны сначала объявить базовые классы (только один на класс, в C # нет смешанного наследования), затем любое количество интерфейсов,таким образом, ваш код должен быть:

public class MyViewModel<T> : MyViewModelBase where T : ModelBase, IMyModel 
0 голосов
/ 15 сентября 2011

Заставьте ModelBase реализовать IMyModel. Если ModelBase не реализует все методы интерфейса, реализуйте их как абстрактные методы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...