Озадаченный дженериками, ковариацией, контравариантностью и др. - PullRequest
0 голосов
/ 29 февраля 2012

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

Давайте возьмем эту иерархическую модель:

class MB { /* ... */ }
class M0 : MB { List<M1> Children; int Prop0;  /* ... */ }
class M1 : MB { List<M2> Children; Guid Prop1; /* ... */ }

и т.д.

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

M0 mroot = new M0();
mroot.Prop0 = 123;

M1 mchild = new M1();
mchild.Prop1 = Guid.NewGuid();
mroot.Children.Add(mchild);

Тогда у меня есть другая иерархическая (view-модель), которая должна «обернуть» вышеприведенную модель:

class VB { /* ... */ }
class V0 : VB { M0 Model; List<V1> Children; /* ... */ }
class V1 : VB { M1 Model; List<V2> Children; /* ... */ }

и т.д.

Теперь рассмотрим коллекцию, целью которой является хранение некоторых узлов модели. Кстати, я хотел бы добавить ссылки несколькими способами: добавив узлы на основе MB, а также узлы на основе VB.

Вкратце, вот как я это сделал:

interface IVM<out T>  where T : MB { T Model }
class VB<T> : VB, IVM<T> where T : MB { T Model; /* ... */ }
class V0 : VB<M0> { List<V1> Children; /* ... */ }
class V1 : VB<M1> { List<V2> Children; /* ... */ }

и т.д.

class MyList : List<MB>
{
  public Add(MB item) { /* ... */ }
  public AddRange(IEnumerable<MB> list) { /* ... */ }
  public Add(IVM<MB> item) { Add(item.Model); }
  public AddRange(IEnumerable<IVM<MB>> list) { foreach (var x in list) Add(x); }
}

На этом этапе модель представления проста, но не подвержена ошибкам:

int x = vroot.Model.Prop0;
Guid y = vroot.Children[0].Model.Prop1;

Даже добавить элементы в коллекцию просто:

list.Add(mchild);
list.Add(vroot.Children);

Я мог бы использовать универсальный VB, такой как:

class VB { MB Model; }

Но я бы также лишился возможности избегать опасных / вводящих в заблуждение приведений:

int x = ((M0)vroot.Model).Prop0;
Guid y = ((M1)vroot.Children[0].Model).Prop1;

Есть какое-нибудь меньшее глупое решение?

Заранее большое спасибо.

РЕДАКТИРОВАТЬ: добавлен код для повышения ясности.

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