Понимание обобщений в сочетании с унаследованными классами - PullRequest
2 голосов
/ 28 января 2011

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

По причинам, связанным с NHibernate, у меня есть базовый абстрактный класс (Listing) и классы, которые наследуют его (Listing_UK, Listing_US и т. Д.).
Они функционально идентичны.
Я понимаю, почему это не работает:

List<Listing> test = new List<Listing_UK>();

Сейчас я делаю эквивалент этого:

List<Listing> test = new List<Listing>();
test.Add(new Listing_UK() as Listing);

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

Я ценю, что основополагающая идея того, что я делаю, немного странная, но есть ли у кого-нибудь совет?

РЕДАКТИРОВАТЬ:

Я явно сделал свои примеры слишком абстрактными.
Я пытался избегать создания этого слишком NHibernate -конкретного, так что это на самом деле отличается от моего другого вопроса(и потому что я думаю, что то, что я спрашиваю, является более фундаментальным), но то, что я в основном хочу достичь, это:

IQueryOver<Listing,Listing> test = null;
if(condition) {
  test = DBSession.QueryOver<Listing_UK>();
} else {
  test = DBSession.QueryOver<Listing_US>();
}
test.Where(l => l.Field == "value").List<Listing>();

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

Ответы [ 3 ]

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

Нет необходимости использовать «как» в коде, который вы получили.Это будет работать нормально:

List<Listing> test = new List<Listing>();
test.Add(new Listing_UK());

Не совсем понятно, что вам нужно делать, чего вы уже не можете делать.Тебе действительно нужен List<Listing_UK>?Какая здесь картина в целом?Если бы вы могли показать какой-то код, который не работает, это помогло бы.

РЕДАКТИРОВАТЬ: Хорошо, теперь, когда вы объяснили немного больше, я подозреваю, что вы хотите универсальный метод:

List<Listing> list = condition ? QueryList<Listing_UK>() 
                               : QueryList<Listing_US>();

private static List<Listing> QueryList<T>() where T : Listing
{
    return DBSession.QueryOver<T>()
                    .Where(l => l.Field == "value")
                    .List<Listing>();
}

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

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

0 голосов
/ 28 января 2011
class Foo : Bar { }

void Test(List<Bar> list);

Помните, что вы можете сделать:

List<Bar> list = new List<Bar>();
Test (list);

но вы не можете:

List<Foo> list = new List<Foo>();
Test (list);

для этого используйте:

void Test2 <T> (List<T> list) where T : Bar    

или

List<Foo> list = new List<Foo>();
Test (list.Cast<Bar>().ToList()); // not ToList<Bar>()
<ч />

Это потому, что

Bar is Bar; // true
Foo is Bar; // true
List<Foo> is List<Foo>; // true
List<Bar> is List<Bar>; // true

но

List<Foo> is List<Bar>; // false!
0 голосов
/ 28 января 2011

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

List<Listing> test = new List<Listing>();
test.Add(new Listing_UK());

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

foreach (Listing listing in test)
{
    listing.Update();
    if (listing is Listing_UK)
        ((Listing_UK)listing).PunchTheQueen();
}

Просто!

...