Can't join 2 descendants under the same collection of their parents

This is my class structure :

public class MainWindow
{
    public List<FirstBar> FirstBars { get; set; }
    public List<Foo> SelectedFoos { get; set; }

    public MainWindow()
    {
        FirstBars = new List<FirstBar>();
        SelectedFoos = new List<Foo>();
    }
}

public abstract class Foo { public bool IsSelected { get; set; } }
public class FirstBar : Foo { public List<SecondBar> SecondBar { get; set; } }
public class SecondBar : Foo { }

...and then I wanna fill in the SelectedFoos with / under this condition(s) :

I want to find all FirstBars which IsSelected==true. And if I found a FirstBar which IsSelected==false, I then look for each SecondBar under FirstBar which IsSelected==true.

So, based on that condition, I wrote this down somewhere after the collection initialization in the MainWindow's constructor :

/*assume below collections are already filled with some items.*/
SelectedFoos = FirstBars.Where(x => x.IsSelected).ToList(); //this is the error, below code is kinda irrelevant.
SelectedFoos.AddRange(FirstBars.Where(x => !x.IsSelected).SelectMany(x => x.SecondBars).Where(x => x.IsSelected).ToList();

But, editor says it's wrong / error :

Cannot implicitly convert type '...FirstBar>' to '...Foo>'

Then, I tried :

/*assume below collections are already filled with some items.*/
SelectedFoos = (List<Foo>)FirstBars.Where(x => x.IsSelected).ToList(); //this is the error, below code is kinda irrelevant.
SelectedFoos.AddRange((List<Foo>)FirstBars.Where(x => !x.IsSelected).SelectMany(x => x.SecondBars).Where(x => x.IsSelected).ToList();

After that the error changed to :

Cannot convert type '...FirstBar>' to '...Foo>'

My reasoning is (which apparently wrong somehow), since they (FirstBar and SecondBar) both have a same parent (Foo), then they can be combined in a list of their parent (List<Foo>).

Btw, I know it can be solved if I split them into different collections, but it's better to have 1 list (since in my real project code, there's also ThirdBar (the collection of this is inside the SecondBar) and FourthBar (the collection of this is inside the ThirdBar).

Can anyone explains what caused this? I feel that I am kinda lost on some fundamental of inheritance with this problem.

Thank you

Jon Skeet
people
quotationmark

The problem has nothing to do with the parents here (and you're not doing a join anyway) - and it's not even in your second line. The problem is just that a List<FirstBar> isn't a List<Foo>, even though every FirstBar is a Foo. As of .NET 4, this is easy to fix using generic covariance:

SelectedFoos = FirstBars.Where(x => x.IsSelected).ToList<Foo>();

The explicit type argument on ToList means this is basically equivalent to:

IEnumerable<FirstBar> tmp = Enumerable.Where<FirstBar>(FirstBars, x => x.IsSelected);
SelectedFoos = Enumerable.ToList<Foo>(tmp);

That's using the fact that an IEnumerable<FirstBar> expression can be converted to IEnumerable<Foo> with covariance.

people

See more on this question at Stackoverflow