Reputation: 2490
For brevity, I will be generic here. I have a base class - Review - that has a child - ShelfAwarenessReview.
I also have a method, whose signature is required by an interface:
public List<Review> GetReviews(string filePath)
{
XElement xmlDoc = XElement.Load(filePath);
var dtos = from item in xmlDoc.Descendants("message")
select new ShelfAwarenessReview()
{
PubDate = item.Element("meta").Attribute("permlinkdate").Value,
Summary = item.Element("meta").Element("summary").Value,
Isbn = item.Element("BookInfo").Element("ISBN").Value
};
List<Review> reviews = new List<Review>();
reviews = dtos.ToList();
return reviews;
}
Now, the error I am getting is that List<ShelfAwarenessReview>
cannot be cast implicitly to List<Review>
.
I have tried several types of casting - or, at least I thought I did - and it doesn't work. I thought because ShelfAwarenessReview is a child of Review that this would work. After all, as the inheritance adage goes, "All toasters are appliances but not all appliances are toasters"...
What do I need to do to get a list of ShelfAwarenessReviews to exit the method in as a list of its parent type (Review)?
Just an FYI, the code calling this method is intended not to care about the types reviews it is getting. The subsequent code will operate on whatever.
I appreciate it big time.
Upvotes: 2
Views: 3218
Reputation: 17691
use this one
List<Review> reviews = dtos.Cast<Review>().ToList();
Upvotes: 1
Reputation: 39013
You can't cast a List to List. Suppose you could, horrible things would happen:
List<String> list = new list<String>();
list.Add("Hello");
List<Object> list2 = List<Object>(list);
list2.Add(12);
Huh? Did I just add an integer to a list of strings. That's why you can't. You should read about covariance and contravariance.
Upvotes: 1
Reputation: 18168
It's the problem of Covariance. For your particular problem, try:
return dtos.ToList().Cast<Review>();
Upvotes: 3
Reputation: 100527
Use Cast to convert to base type:
return dtos.Cast<Review>().ToList();
Upvotes: 3
Reputation: 1499810
Well to start with, you don't need to create an empty List<Review>
which you then ignore :)
Here's the simplest solution:
public List<Review> GetReviews(string filePath)
{
XElement xmlDoc = XElement.Load(filePath);
var dtos = ...; // As before
return dtos.Cast<Review>().ToList();
}
If you're using .NET 4 and C# 4, there's another alternative due to generic covariance which works for IEnumerable<T>
but not List<T>
:
public List<Review> GetReviews(string filePath)
{
XElement xmlDoc = XElement.Load(filePath);
IEnumerable<Review> dtos = ...; // As before
return dtos.ToList();
}
Note the explicit specification of the type of dtos
. The query expression will be of type IEnumerable<ShelfAwarenessReview>
but that's implicitly convertible (in C# 4) to IEnumerable<Review>
.
Upvotes: 6
Reputation: 245389
Change:
reviews = dtos.ToList();
To:
reviews = dtos.Cast<Review>().ToList();
The problem is that List and List are not covariant. It's easy to understand if you think about it:
List<ShelfAwarenessReview> initial = new List<ShelfAwarenessReview>();
List<Review> cast = (List<Review>)initial;
// The underlying type is still List<ShelfAwarenessReview>.
// SomeOtherReview inherits Review but not ShelfAwarenessReview
// What will happen when I make the following call?
cast.Add(new SomeOtherReview());
Upvotes: 3