возникли проблемы с совместимостью заданий?

1

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

public interface IView
{
   int Id { get; set; }
}

то у меня есть модель домена, которая реализует этот интерфейс

public class View: IView
{
   public int Id { get; set; }
}

то у меня есть несколько классов, которые наследуют от базового класса

public class ViewA: View
{ 
   public string PropertyA { get; set; }
}

а также

public class ViewB: View
{
   public string PropertyB { get; set; }
}

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

var views = new List<IView>();

и создать представление из моей базы, поскольку ViewA и ViewB имеют идентификаторы

var view = new View();
view.Id = 1;

теперь я пытаюсь применить это к ViewA, поэтому я могу установить свойствоA так:

var viewA = (ViewA)view;

но отладчик говорит мне, что я не могу использовать "view" для ViewA (это просто компилируется).

Unable to cast object of type 'View' to type 'ViewA'

Я уверен, что мне не хватает чего-то в моем понимании интерфейса → наследование базового класса, но я подумал, что вы можете использовать класс "lesser" для "более определенного" класса. чтение о ковариации, контравариантности и совместимости присвоений, я бы подумал, что я должен это сделать; видимо, нет..

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

Я бы предпочел не дублировать свойства в ViewA и ViewB, это то, что я пытаюсь сделать возможным, или просто у меня все это неправильно?

Теги:
polymorphism
inheritance

4 ответа

3
Лучший ответ

Я уверен, что мне не хватает чего-то в моем понимании интерфейса → наследование базового класса, но я подумал, что вы можете использовать класс "lesser" для "более определенного" класса. чтение о ковариации, контравариантности и совместимости присвоений, я бы подумал, что я должен это сделать; видимо, нет..

У вас есть это назад (я думаю). Вы всегда можете отнести экземпляр производного типа к базовому типу, но не наоборот. Если вы передаете экземпляр производному типу, он должен быть экземпляром этого типа во время выполнения.

Похоже, что вы пытаетесь сделать, так или иначе создать экземпляр ViewA из экземпляра View. Это не так, как работает литье.

Вот пример, который мог бы сработать, что могло бы помочь. Если у вас есть список просмотров:

var views = new List<IView>();

И вы добавляете экземпляр ViewA:

views.Add(new ViewA());

Теперь компилятор не "знает", что views[0] - это ViewA --it список IView конце концов. В этом случае вы знаете больше, чем компилятор, и листинг подходит:

var viewA = (ViewA)views[0];

Вы также отмечаете:

Я бы предпочел не дублировать свойства в ViewA и ViewB

Если я что-то не упустил, вы не дублировали никаких свойств. ViewA и ViewB имеют разные свойства и наследуют свойство Id из класса View.

Другими словами, это выглядит хорошо:

var view = new ViewA();

view.Id = 4;
  • 0
    так как же мне обойти дублирование настройки идентификатора? скажем, у меня есть это приведение в операторе switch некоторого свойства, которое говорит мне, какое преобразование нужно сделать, поэтому мне не нужно устанавливать Id в обоих местах. это можно сделать, или я просто должен установить Id в обоих местах?
  • 0
    @JoshMeiburg: я только добавил немного в конец своего ответа. Id наследуется ViewA и ViewB из класса View . Вам не нужно переопределять это свойство в ViewA или ViewB .
Показать ещё 4 комментария
1

Добавить экземпляры ViewA и ViewB к списку, а не просто как View:

var views = new List<IView>();

var view = new ViewA();  // add an instance of viewA
views.Add(view);

Вы можете получить доступ к элементу напрямую (без кастинга, спасибо Andrew), чтобы изменить свойство "Id" в базовом классе, так как свойство также определено в интерфейсе:

var view = (View)views[0];
view.Id = 999;

Или проверьте тип, чтобы получить доступ к другим более конкретным свойствам:

var viewB = views[0] as ViewB;  // first element is a ViewA, so viewB is null

if (viewB != null)
{
    viewB.PropertyB = "someValue";  // doesn't run because viewB is null
}

var viewA = views[0] as ViewA;

if (viewA != null)
{
    viewA.PropertyA = "someOtherValue";  // runs - you have an instance of viewA
}
  • 1
    Свойство Id определено в интерфейсе, поэтому вам не нужно приводить к представлению View во втором фрагменте
  • 0
    Спасибо Андрей! Исправлена.
0

Нет, вы не можете отнести "меньший" класс к "более определенному" классу. Но вы можете отображать viewA и viewB в список View, чтобы когда вы могли получить общие свойства.

0

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

Итак, вы создаете свой экземпляр как:

var view = new View();

Потому что он наследует IView вы можете ссылаться на него, как и View, но он никогда не меняется от ее типа View.

Поэтому, когда вы пытаетесь использовать его как ViewA он терпит неудачу. Это никогда не будет ViewA если вы не создали его как таковой.

Поэтому, если вы это сделаете:

var view = new ViewA();

Затем на него можно ссылаться как на IView, View или ViewA, но он всегда будет иметь вид ViewA.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню