2

This is a question related to another one I asked that was specific to NHibernate, but I'm starting to think that my question might be far more fundamental than that.

ForNHibernate-related reasons, I have a base abstract class (Listing) and classes that inherit from it (Listing_UK, Listing_US, etc).
These are functionally identical.
I understand why this does not work:

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

Right now I'm doing the equivalent of this:

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

which works, but I need the classes to be more interchangeable, like the above.

I appreciate that the fundamental idea behind what I'm doing is a little weird, but does anyone have any advice?

EDIT:

I've clearly made my examples way too abstract.
I was trying to avoid making this too NHibernate-specific so that it's actually different from my other question (and because I think what I'm asking is more fundamental), but what I basically want to achieve is this:

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>();

From the reactions I am getting here, I'm reasonably sure that what I'm asking for is not possible.

Community
  • 1
  • 1
Alastair
  • 5,894
  • 7
  • 34
  • 61
  • What do you find to be problematic about your second example? (Obviously the cast is unnecessary.) – mqp Jan 28 '11 at 15:20
  • Might help a bit if you show the code for `Listing_UK` – jgauffin Jan 28 '11 at 15:20
  • As I posted in the comment to Jon Skeet... I think I've over-simplified this example. The question I linked to sort of covers it, though it's very NHibernate-specific. It has a QueryOver object that I want to be able to use as QueryOver and QueryOver interchangeably. I suspect I am asking for the impossible, though... – Alastair Jan 28 '11 at 15:28
  • oh, THATS your problem? you should have made that more clear haha. my answer below isn't really very useful in that case. – Joshua Evensen Jan 28 '11 at 15:31
  • What is `List()`? Maybe `ToList()`? – abatishchev Jan 28 '11 at 15:38
  • @abatischev- it's an NHibernate internal thing. This is why I wanted to keep my example more abstract. – Alastair Jan 28 '11 at 15:42

3 Answers3

1

There's no need to use "as" in the code you've got. This will work fine:

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

It's not really clear what you need to do which you can't do already. Do you actually need a List<Listing_UK>? What's the bigger picture here? If you could show some code which doesn't work, that would help.

EDIT: Okay, now that you've explained a bit more, I suspect you want a generic method:

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>();
}

I don't know NHibernate well enough to know whether that's enough already, but if not I'm sure you could adjust it slightly.

Your original thought of just trying to treat the types interchangably really isn't going to work.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Yes, sorry, I was using the "as" to demonstrate what I was trying to achieve. My bigger picture is outlined in the linked question, though it's very NHibernate specific. Basically, it has a QueryOver object, and I'd like to be able to freely switch between QueryOver and QueryOver. I'm suspecting that what I want isn't possible, though- from a pure programming perspective using separate classes so that my data ends up in different tables is kind of crazy... – Alastair Jan 28 '11 at 15:24
  • The way you're describing it, I guess I would expect to take `test` as a `List` and then use `test.OfType()`, `test.OfType()`, etc. as necessary. But I really don't understand what you're talking about. – mqp Jan 28 '11 at 15:27
  • @Alastair: No, you're *not* going to be able to switch freely between them... you say that you know why `List test = new List();` doesn't work - so that's why you're not going to be able to switch freely between them. But what do you need to *do* with them? – Jon Skeet Jan 28 '11 at 15:27
  • I've edited the original question- I've obviously been way too abstract in my examples... – Alastair Jan 28 '11 at 15:37
  • OK, thanks. This is definitely the kind of direction I need to be heading in, and it makes sense. Flagging it as the answer! – Alastair Jan 28 '11 at 15:53
0

If Listing_UK inherits from the abstract class Listing, you don't need to do any casting when you add it to your List. Downcasts like that are implicit.

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

Then when you want to deal with each Listing, you'll just have to deal with their types at that point.

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

Simple!

Joshua Evensen
  • 1,544
  • 1
  • 15
  • 33
0
class Foo : Bar { }

void Test(List<Bar> list);

Remember that you can do:

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

but you can't:

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

to achieve that, use:

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

or

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

That's because

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

but

List<Foo> is List<Bar>; // false!
abatishchev
  • 98,240
  • 88
  • 296
  • 433