简体   繁体   English

如果实现接口的类将使用List <T>,为什么在接口定义中使用IEnumerable <T>?

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

I am currently working through a .NET Web API tutorial located here . 我目前正在通过此处的.NET Web API教程进行操作。 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> ? 我的问题是,为什么编写接口以便GetAll()返回IEnumerable<Product>如果实现将特意在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). 我假设这是为了促进重用,以便其他一些IProductRepository实现可以使用不同的IEnumerable<Product> (虽然这样的例子会很好,因为我想不到一个,不是我怀疑它存在,我'我只是没有超经验)。

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() ? 框架或编译器是否无法看到public List<Product> GetAll()是否可从public IEnumerable<Product> GetAll()

Two main reasons: 两个主要原因:

  • this hides the actual implementation so that the consumer doesn't do anything they shouldn't with the data (eg 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. 显然,消费者可以将结果转换为List<T> ,但是它们将依赖于未记录的实现细节,因此如果您稍后更改它并且它会破坏它们的代码,那将是他们的错。
  • 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. 如果有一天你需要改变实现以使用List<T>以外的东西,你可以在没有消费者任何明显变化的情况下进行。

您希望更改List<T>以通过存储库方法进行操作,而不是让用户直接访问List<T> - 因此,您返回IEnumerable<T>以便它们无法更改基础集合

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM