То, что я пытаюсь сделать, это использовать один вызов, чтобы вернуть коллекцию из двух расширений базового класса. Вот что у меня есть:
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, это то, что я пытаюсь сделать возможным, или просто у меня все это неправильно?
Я уверен, что мне не хватает чего-то в моем понимании интерфейса → наследование базового класса, но я подумал, что вы можете использовать класс "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;
Добавить экземпляры 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
}
Id
определено в интерфейсе, поэтому вам не нужно приводить к представлению View
во втором фрагменте
Нет, вы не можете отнести "меньший" класс к "более определенному" классу. Но вы можете отображать viewA и viewB в список View, чтобы когда вы могли получить общие свойства.
Тип, который вы используете для создания объекта, является типом, которым он всегда должен быть - он никогда не изменяется.
Итак, вы создаете свой экземпляр как:
var view = new View();
Потому что он наследует IView
вы можете ссылаться на него, как и View
, но он никогда не меняется от ее типа View
.
Поэтому, когда вы пытаетесь использовать его как ViewA
он терпит неудачу. Это никогда не будет ViewA
если вы не создали его как таковой.
Поэтому, если вы это сделаете:
var view = new ViewA();
Затем на него можно ссылаться как на IView
, View
или ViewA
, но он всегда будет иметь вид ViewA
.
Id
наследуетсяViewA
иViewB
из классаView
. Вам не нужно переопределять это свойство вViewA
илиViewB
.