C# 为什么在多对多/一对多关系上使用 ICollection 而不是 IEnumerable 或 List<T> ?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10113244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 12:29:06  来源:igfitidea点击:

Why use ICollection and not IEnumerable or List<T> on many-many/one-many relationships?

c#entity-frameworkcode-firsticollection

提问by Jan Carlo Viray

I see this a lot in tutorials, with navigation properties as ICollection<T>.

我在教程中经常看到这种情况,导航属性为ICollection<T>.

Is this a mandatory requirement for Entity Framework? Can I use IEnumerable?

这是实体框架的强制性要求吗?我可以使用IEnumerable吗?

What's the main purpose of using ICollectioninstead of IEnumerableor even List<T>?

使用ICollection而不是IEnumerable甚至是的主要目的是List<T>什么?

采纳答案by Travis J

Usually what you choose will depend on which methods you need access to. In general - IEnumerable<>(MSDN: http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx) for a list of objects that only needs to be iterated through, ICollection<>(MSDN: http://msdn.microsoft.com/en-us/library/92t2ye13.aspx) for a list of objects that needs to be iterated through and modified, List<>for a list of objects that needs to be iterated through, modified, sorted, etc (See here for a full list: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx).

通常,您选择什么取决于您需要访问哪些方法。一般来说 - IEnumerable<>(MSDN:http: //msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx)用于只需要迭代的对象列表,ICollection<>(MSDN:http:// msdn.microsoft.com/en-us/library/92t2ye13.aspx)获取需要迭代和修改List<>的对象列表,获取需要迭代、修改、排序等的对象列表(参见此处完整列表:http: //msdn.microsoft.com/en-us/library/6sh2ey19.aspx)。

From a more specific standpoint, lazy loading comes in to play with choosing the type. By default, navigation properties in Entity Framework come with change tracking and are proxies. In order for the dynamic proxy to be created as a navigation property, the virtual type mustimplement ICollection.

从更具体的角度来看,延迟加载与选择类型有关。默认情况下,实体框架中的导航属性带有更改跟踪并且是代理。为了将动态代理创建为导航属性,虚拟类型必须实现ICollection.

A navigation property that represents the "many" end of a relationship must return a type that implements ICollection, where T is the type of the object at the other end of the relationship. -Requirements for Creating POCO ProxiesMSDN

表示关系“多”端的导航属性必须返回实现 ICollection 的类型,其中 T 是关系另一端的对象类型。-创建 POCO 代理的要求MSDN

More information on Defining and Managing RelationshipsMSDN

有关定义和管理关系MSDN 的更多信息

回答by Justin Niessner

ICollection<T>is used because the IEnumerable<T>interface provides no way of adding items, removing items, or otherwise modifying the collection.

ICollection<T>之所以使用,是因为该IEnumerable<T>接口没有提供添加项目、删除项目或以其他方式修改集合的方法。

回答by Tigran

The basic idea of using ICollectionis a provide an interface to readonly-access to some finite amount of data. In fact you have a ICollection.Countproperty. IEnumerableis more suitable for some chain of the data where you read till some logical point, some condition esplicitly specified by consumer or till the end of the enumeration.

使用的基本思想ICollection是提供一个接口来只读访问一些有限数量的数据。事实上,您有一个ICollection.Count属性。IEnumerable更适合您阅读的某些数据链,直到某个逻辑点,消费者明确指定的某些条件或直到枚举结束。

回答by phoog

Responding to your question about List<T>:

回答您关于 的问题List<T>

List<T>is a class; specifying an interface allows more flexibility of implementation. A better question is "why not IList<T>?"

List<T>是一个类;指定接口允许更灵活的实现。一个更好的问题是“为什么不IList<T>呢?”

To answer that question, consider what IList<T>adds to ICollection<T>: integer indexing, which means the items have some arbitrary order, and can be retrieved by reference to that order. This is probably not meaningful in most cases, since items probably need to be ordered differently in different contexts.

要回答这个问题,请考虑IList<T>添加到以下内容的内容ICollection<T>:整数索引,这意味着项目具有任意顺序,并且可以通过引用该顺序进行检索。这在大多数情况下可能没有意义,因为在不同的上下文中可能需要对项目进行不同的排序。

回答by yardpenalty.com

What I have done in the past is declare my inner class collections using IList<Class>, ICollection<Class>or IEnumerable<Class>(if static list) depending on whether or not I will have to do any number of the following in a method in my repository: enumerate, sort/order or modify. When I just need to enumerate (and maybe sort) over objects then I create a temp List<Class>to work with the collection within an IEnumerable method. I think this practice would only be effective if the collection is relatively small, but it may be good practice in general, idk. Please correct me if there is evidence as to why this would not good practice.

我过去所做的是使用IList<Class>,ICollection<Class>IEnumerable<Class>(如果是静态列表)声明我的内部类集合,具体取决于我是否必须在我的存储库中的方法中执行以下任意数量的操作:枚举、排序/排序或修改. 当我只需要枚举(或者排序)对象时,我会创建一个临时对象List<Class>来处理 IEnumerable 方法中的集合。我认为这种做法只有在集合相对较小的情况下才会有效,但总的来说,idk 可能是很好的做法。如果有证据表明为什么这不是好的做法,请纠正我。

回答by user3918295

I remember it this way:

我记得是这样的:

  1. IEnumerable has one method GetEnumerator() which allows one to read through the values in a collection but not write to it. Most of the complexity of using the enumerator is taken care of for us by the for each statement in C#. IEnumerable has one property: Current, which returns the current element.

  2. ICollection implements IEnumerable and adds few additional properties the most use of which is Count. The generic version of ICollection implements the Add() and Remove() methods.

  3. IList implements both IEnumerable and ICollection, and add the integer indexing access to items (which is not usually required, as ordering is done in database).

  1. IEnumerable 有一个 GetEnumerator() 方法,它允许读取集合中的值,但不能写入集合中的值。C# 中的 for each 语句为我们处理了使用枚举器的大部分复杂性。IEnumerable 有一个属性:Current,它返回当前元素。

  2. ICollection 实现了 IEnumerable 并添加了几个额外的属性,其中最常用的是 Count。ICollection 的通用版本实现了 Add() 和 Remove() 方法。

  3. IList 实现了 IEnumerable 和 ICollection,并添加了对项目的整数索引访问(通常不需要,因为排序是在数据库中完成的)。

回答by Ramakrishnan

There are some basics difference between ICollection and IEnumerable

ICollection 和 IEnumerable 之间有一些基本区别

  • IEnumerable- contains only GetEnumerator method to get Enumerator and allows looping
  • ICollectioncontains additional methods: Add, Remove, Contains, Count, CopyTo
  • ICollectionis inherited from IEnumerable
  • With ICollection you can modify the collection by using the methods like add/remove. You don't have the liberty to do the same with IEnumerable.
  • IEnumerable- 只包含 GetEnumerator 方法来获取 Enumerator 并允许循环
  • ICollection包含其他方法:Add、Remove、Contains、Count、CopyTo
  • ICollection继承自 IEnumerable
  • 使用 ICollection,您可以使用添加/删除等方法修改集合。你没有自由对 IEnumerable 做同样的事情。

Simple Program:

简单程序:

using System;
using System.Collections;
using System.Collections.Generic;

namespace StackDemo
{
    class Program 
    {
        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();
            persons.Add(new Person("John",30));
            persons.Add(new Person("Hyman", 27));

            ICollection<Person> personCollection = persons;
            IEnumerable<Person> personEnumeration = persons;

            // IEnumeration
            // IEnumration Contains only GetEnumerator method to get Enumerator and make a looping
            foreach (Person p in personEnumeration)
            {                                   
               Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);
            }

            // ICollection
            // ICollection Add/Remove/Contains/Count/CopyTo
            // ICollection is inherited from IEnumerable
            personCollection.Add(new Person("Tim", 10));

            foreach (Person p in personCollection)
            {
                Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);        
            }
            Console.ReadLine();

        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
}

回答by LewisAntonio803

Navigation properties are typically defined as virtual so that they can take advantage of certain Entity Framework functionality such as lazy loading.

导航属性通常定义为虚拟的,以便它们可以利用某些实体框架功能,例如延迟加载。

If a navigation property can hold multiple entities (as in many-to-many or one-to-many relationships), its type must be a list in which entries can be added, deleted, and updated, such as ICollection.

如果导航属性可以包含多个实体(如在多对多或一对多关系中),则其类型必须是可以在其中添加、删除和更新条目的列表,例如 ICollection。

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net- mvc-应用程序

回答by user11336341

Lets try thinking outside of the box with/by logic and understand clearly these three interfaces in your question:

让我们尝试使用/通过逻辑跳出框框思考,并清楚地理解您问题中的这三个接口:

When the class of some instance implements the System.Collection.IEnumerable interface then, in simple words, we can say that this instance is both enumerable and iterable, which means that this instance allows somehow in a single loop to go/get/pass/traverse/iterate over/through all the items and elements that this instance contains.

当某个实例的类实现了 System.Collection.IEnumerable 接口时,简单来说,我们可以说这个实例既可枚举又可迭代,这意味着该实例允许在单个循环中以某种方式 go/get/pass/遍历/迭代/遍历此实例包含的所有项目和元素。

This means that this is also possible to enumerate all the items and elements that this instance contains.

这意味着也可以枚举此实例包含的所有项目和元素。

Every class that implements the System.Collection.IEnumerable interface also implements the GetEnumerator method that takes no arguments and returns an System.Collections.IEnumerator instance.

每个实现 System.Collection.IEnumerable 接口的类还实现了 GetEnumerator 方法,该方法不接受任何参数并返回一个 System.Collections.IEnumerator 实例。

Instances of System.Collections.IEnumerator interface behaves very similar to C++ iterators.

System.Collections.IEnumerator 接口的实例与 C++ 迭代器的行为非常相似。

When the class of some instance implements the System.Collection.ICollection interface then, in simple words, we can say that this instance is some collection of things.

当某个实例的类实现了 System.Collection.ICollection 接口时,简单来说,我们可以说这个实例是一些事物的集合。

The generic version of this interface, i.e. System.Collection.Generic.ICollection, is more informative because this generic interface explicitly states what is the type of the things in the collection.

此接口的通用版本,即 System.Collection.Generic.ICollection,提供更多信息,因为此通用接口明确说明集合中事物的类型。

This is all reasonable, rational, logical and makes sense that System.Collections.ICollection interface inherits from System.Collections.IEnumerable interface, because theoretically every collection is also both enumerable and iterable and this is theoretically possible to go over all the items and elements in every collection.

System.Collections.ICollection 接口继承自 System.Collections.IEnumerable 接口都是合理、合理、合乎逻辑的,因为理论上每个集合也是可枚举和可迭代的,理论上可以遍历所有项目和元素在每个集合中。

System.Collections.ICollection interface represents a finite dynamic collection that are changeable, which means that exist items can be removed from the collection and new items can be added to the same collection.

System.Collections.ICollection 接口表示一个可变的有限动态集合,这意味着可以从集合中删除现有项目,并且可以将新项目添加到同一个集合中。

This explains why System.Collections.ICollection interface has the "Add" and "Remove" methods.

这解释了为什么 System.Collections.ICollection 接口具有“Add”和“Remove”方法。

Because that instances of System.Collections.ICollection interface are finite collections then the word "finite" implies that every collection of this interface always has a finite number of items and elements in it.

因为 System.Collections.ICollection 接口的实例是有限集合,所以“有限”一词意味着该接口的每个集合中始终包含有限数量的项目和元素。

The property Count of System.Collections.ICollection interface supposes to return this number.

System.Collections.ICollection 接口的属性 Count 假设返回这个数字。

System.Collections.IEnumerable interface does not have these methods and properties that System.Collections.ICollection interface has, because it does not make any sense that System.Collections.IEnumerable will have these methods and properties that System.Collections.ICollection interface has.

System.Collections.IEnumerable 接口没有 System.Collections.ICollection 接口具有的这些方法和属性,因为 System.Collections.IEnumerable 将具有 System.Collections.ICollection 接口具有的这些方法和属性没有任何意义。

The logic also says that every instance that is both enumerable and iterable is not necessarily a collection and not necessarily changeable.

逻辑还说,每个既可枚举又可迭代的实例不一定是集合,也不一定是可变的。

When I say changeable, I mean that don't immediately think that you can add or remove something from something that is both enumerable and iterable.

当我说可变时,我的意思是不要立即认为您可以从既可枚举又可迭代的东西中添加或删除某些东西。

If I just created some finite sequence of prime numbers, for example, this finite sequence of prime numbers is indeed an instance of System.Collections.IEnumerable interface, because now I can go over all the prime numbers in this finite sequence in a single loop and do whatever I want to do with each of them, like printing each of them to the console window or screen, but this finite sequence of prime numbers is not an instance of System.Collections.ICollection interface, because this is not making sense to add composite numbers to this finite sequence of prime numbers.

例如,如果我只是创建了一些有限质数序列,那么这个有限质数序列确实是 System.Collections.IEnumerable 接口的一个实例,因为现在我可以在一个循环中遍历这个有限序列中的所有质数并对它们中的每一个做我想做的任何事情,例如将它们中的每一个打印到控制台窗口或屏幕上,但是这个有限的质数序列不是 System.Collections.ICollection 接口的实例,因为这没有意义将合数添加到这个有限的素数序列中。

Also you want in the next iteration to get the next closest larger prime number to the current prime number in the current iteration, if so you also don't want to remove exist prime numbers from this finite sequence of prime numbers.

您还希望在下一次迭代中获得与当前迭代中当前素数最接近的较大素数,如果是这样,您也不希望从这个有限的素数序列中删除现有的素数。

Also you probably want to use, code and write "yield return" in the GetEnumerator method of the System.Collections.IEnumerable interface to produce the prime numbers and not allocating anything on the memory heap and then task the Garbage Collector (GC) to both deallocate and free this memory from the heap, because this is obviously both waste of operating system memory and decreases performance.

此外,您可能希望在 System.Collections.IEnumerable 接口的 GetEnumerator 方法中使用、编码和编写“收益回报”以生成素数而不在内存堆上分配任何内容,然后将垃圾收集器 (GC) 分配给两者从堆中释放和释放这些内存,因为这显然既浪费操作系统内存又降低性能。

Dynamic memory allocation and deallocation on the heap should be done when invoking the methods and properties of System.Collections.ICollection interface, but not when invoking the methods and properties of System.Collections.IEnumerable interface (although System.Collections.IEnumerable interface has only 1 method and 0 properties).

堆上的动态内存分配和释放应该在调用 System.Collections.ICollection 接口的方法和属性时进行,而不是在调用 System.Collections.IEnumerable 接口的方法和属性时(虽然 System.Collections.IEnumerable 接口只有1 个方法和 0 个属性)。

According to what others said in this Stack Overflow webpage, System.Collections.IList interface simply represents an orderablecollection and this explains why the methods of System.Collections.IList interface work with indexes in contrast to these of System.Collections.ICollection interface.

根据其他人在 Stack Overflow 网页中所说的, System.Collections.IList 接口只是表示一个可排序的集合,这解释了为什么 System.Collections.IList 接口的方法与 System.Collections.ICollection 接口的方法相比使用索引。

In short System.Collections.ICollection interface does not imply that an instance of it is orderable, but System.Collections.IList interface does imply that.

简而言之 System.Collections.ICollection 接口并不暗示它的实例是可订购的,但 System.Collections.IList 接口确实暗示了这一点。

Theoretically ordered set is special case of unordered set.

理论上有序集是无序集的特例。

This also makes sense and explains why System.Collections.IList interface inherits System.Collections.ICollection interface.

这也是有道理的,并解释了为什么 System.Collections.IList 接口继承 System.Collections.ICollection 接口。