Why would one use IEnumerable<T> in an interface definition if the class implementing the interface will be using List<T>?

StackOverflow https://stackoverflow.com/questions/21609858

Question

I am currently working through a .NET Web API tutorial located here. In the example, we have an interface defined in a model class like so:

namespace ProductStore.Models
{
    public interface IProductRepository
    {
        IEnumerable<Product> GetAll();
        Product Get(int id);
        Product Add(Product item);
        void Remove(int id);
        bool Update(Product item);
    }
}

Then, later in the tutorial, we implement this interface like so:

namespace ProductStore.Models
{
    public class ProductRepository : IProductRepository
    {
        private List<Product> products = new List<Product>();
        private int _nextId = 1;

        public ProductRepository()
        {
            Add(new Product { Name = "Tomato soup", Category = "Groceries", Price = 1.39M });
            Add(new Product { Name = "Yo-yo", Category = "Toys", Price = 3.75M });
            Add(new Product { Name = "Hammer", Category = "Hardware", Price = 16.99M });
        }

        public IEnumerable<Product> GetAll()
        {
            return products;
        }

        public Product Get(int id)
        {
            return products.Find(p => p.Id == id);
        }

        public Product Add(Product item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            item.Id = _nextId++;
            products.Add(item);
            return item;
        }

        public void Remove(int id)
        {
            products.RemoveAll(p => p.Id == id);
        }

        public bool Update(Product item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            int index = products.FindIndex(p => p.Id == item.Id);
            if (index == -1)
            {
                return false;
            }
            products.RemoveAt(index);
            products.Add(item);
            return true;
        }
    }
}

My question is, why is the interface written so that GetAll() returns IEnumerable<Product> if the implementation is going to be specifically operating on a List<Product>?

I am assuming this is to facilitate reuse so that some other IProductRepository implementation could use a different IEnumerable<Product> (though an example of this would be nice, because I can't think of one, not that I doubt it exists, I'm just not ultra experienced).

Assuming reuse is the goal indeed, then why is the implementation written like this:

public IEnumerable<Product> GetAll()
{
    return products;
}

Instead of like this:

public List<Product> GetAll()
{
    return products;
}

Does the framework or compiler not have the ability to see that public List<Product> GetAll() is derivable from public IEnumerable<Product> GetAll()?

Was it helpful?

Solution

Two main reasons:

  • this hides the actual implementation so that the consumer doesn't do anything they shouldn't with the data (e.g. add or remove items directly from the list). Obviously, the consumer can cast the result to List<T>, but they would be relying on an undocumented implementation detail, so if you change it later and it breaks their code, it will be their fault.
  • if someday you need to change the implementation to use something other than a List<T>, you can do it without any visible change for the consumer.

OTHER TIPS

You want changes to your List<T> to operate through your repository methods and not give the user direct access to the List<T> - thus, you return an IEnumerable<T> so that they cannot change the underlying collection

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top