Reputation: 5784
With the following code, I receive an "unable to implicitly cast" compilation error on the "return books;" line.
I thought that because am returning a list of book objects that implement IPublication this should work fine?
public interface IPublication {}
public class Book : IPublication {}
public List<IPublication> GetBooks()
{
List<Book> books = new List<Book>();
return books;
}
I note that if I return a single book as a single IPublication object it works fine. Introducing the List<>
requires the explicit cast.
As a workaround I am using:
return books.Cast<IPublication>().ToList();
Upvotes: 11
Views: 13741
Reputation: 86718
The problem is that a List<IPublication>
is something that can hold any class that inherits from IPublication
. Since the compiler doesn't know that you won't try to put a Magazine
into the result of GetBooks()
, you have to write your function like this:
public List<IPublication> GetBooks()
{
List<IPublication> books = new List<IPublication>();
// put only books in here
return books;
}
If your function returns an immutable list that doesn't need to be accessed by index (and you're on C# 4), you can write it like this:
public IEnumerable<IPublication> GetBooks()
{
List<Book> books = new List<Book>();
return books;
}
If you can return an IEnumerable<T>
but you're using C# 3, you can do what cdhowie suggests:
public IEnumerable<IPublication> GetBooks()
{
List<Book> books = new List<Book>();
return books.Cast<IPublication>();
}
If you're using C# 2, it's better to just use the first method I proposed.
Upvotes: 13
Reputation: 284786
That's not a safe conversion. Imagine if someone put a magazine in your list of books.
public class Library
{
public List<Book> books = new List<Book>();
public List<IPublication> GetBooks()
{
return books;
}
}
Elsewhere,
Magazine mag = ...;
List<IPublication> pubs = someLibrary.GetBooks()
pubs.Add(mag);
In .NET 4, you can return a IEnumerable<IPublication>
, as described here, without creating any new objects. cdhowie also gives a good work-around for lower versions. Just drop the .ToList()
, and return an IEnumerable
.
I realize your particular case is safe. But the compiler can't verify that.
Upvotes: 2
Reputation: 168988
You will have to use your workaround unless you are on .NET 4.
Consider if someone were to do this:
public class Magazine : IPublication { }
// Somewhere...
var foo = something.GetBooks();
foo.Add(new Magazine());
If the runtime allowed the conversion from List<Book>
to List<IPublication>
, then you would be allowed to add magazines to a list of books! This breaks the type system, because if something still had a reference to the List<Book>
, it would rightly not expect a Magazine
to be in it, it would treat the Magazine
as though it were a book, and then runtime crashes (or worse -- data corruption or unsafe things) would ensue.
Upvotes: 2
Reputation: 43523
I think you are working on old versions instead of c# 4.0 where we have covariance and contravariance. So you can only convert the list element by element.
Upvotes: 0