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
FirstBar
s whichIsSelected==true
. And if I found aFirstBar
whichIsSelected==false
, I then look for eachSecondBar
underFirstBar
whichIsSelected==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
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.
See more on this question at Stackoverflow