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();
If an interface is defined to be the return type of a method then instances of classes derived from that interface can be returned. The benefit of doing that is no different from returning objects of classes derived from a class.
Interface types act like class types. You can declare variables to be of an interface type, you can declare arguments of methods to accept interface types, and you can even specify that the return type of a method is an interface type.
e.g. is the following code correct where array of interface is being returned. public interface Interface { int Type { get; } string Name { get; } } public override Interface[] ShowValue(int a) { . . } (1) Yes. (2) Because it allows polymorphic behaviour.
Note: You also can use interface names as return types. In this case, the object returned must implement the specified interface.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With