Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I properly return a List of Interfaces type?

Tags:

c#

list

interface

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();
like image 700
dan Avatar asked Nov 25 '10 04:11

dan


People also ask

What is the return type of interface?

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.

Can interface methods have a return type?

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.

How do I return an interface object in C#?

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.

Can we have return type as interface in Java?

Note: You also can use interface names as return types. In this case, the object returned must implement the specified interface.


3 Answers

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.

like image 155
Gabe Avatar answered Oct 03 '22 23:10

Gabe


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.

like image 35
Matthew Flaschen Avatar answered Oct 03 '22 23:10

Matthew Flaschen


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.

like image 32
cdhowie Avatar answered Oct 04 '22 00:10

cdhowie