为什么在多对多关系中使用ICollection而不使用IEnumerable或List <T>?


359

我在教程中看到了很多,导航属性为ICollection<T>

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

使用ICollection代替IEnumerable或什至的主要目的是List<T>什么?

Answers:


439

通常,您选择的内容取决于您需要使用的方法。通常,- IEnumerable<>(MSDN:http : //msdn.microsoft.com/zh-cn/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)。

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

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

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


2
因此,它List应该会好很多,是吗?
Jan Carlo Viray 2012年

3
@JanCarloViray-我倾向于使用List很多。尽管开销最大,但功能最多。
特拉维斯J

1
列表的定义更多地是通过其索引器而不是通过对列表进行排序的能力来实现的(具有整数索引器使对某些内容进行排序变得容易,但这不是必需的)。
phoog 2012年

2
关于您的编辑,将属性限制为接口类型不是关于内存,而是关于封装。考虑:private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };使用与private List<int> _integers = new List<int> { 1, 2, 3 };
phoog

13
@TravisJ:List<T>有一个GetEnumerator()方法,与其实现的方法分开IEnumerable<T>,它返回一个可变的结构类型List<T>.Enumerator。在大多数情况下,该类型的性能将比独立堆对象好一些。鸭式枚举器(如C#和vb.net一样)的编译器在生成foreach代码时可以利用此优势。如果将List<T>强制转换IEnumrable<T>foreach,则该IEnumerable<T>.GetEnumerator()方法将返回一个已分配堆的对象,从而使优化变得不可能。
2012年

85

ICollection<T>之所以使用,是因为该IEnumerable<T>界面无法提供添加项,删除项或修改集合的方式。


3
与List <T>进行比较呢?
Jan Carlo Viray 2012年

12
List<T>实施ICollection<T>
消费者2012年

非泛型ICollection不允许任何方式添加项目,但是它仍然是一个有用的辅助,IEnumerable<T>因为它提供的Count成员通常比枚举所有对象快得多。请注意,如果将IList<Cat>ICollection<Cat>传递给期望使用的代码IEnumerable<Animal>,则Count()扩展方法如果实现了非泛型ICollection,则将很快,但如果仅实现了泛型接口,ICollection<Cat>则不会,因为典型的将不会实现ICollection<Animal>
supercat 2012年

58

回答关于List<T>以下问题:

List<T>是一堂课 指定接口可以实现更高的灵活性。一个更好的问题是“为什么不IList<T>呢?”

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


21

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

  • IEnumerable-仅包含用于获取Enumerator的GetEnumerator方法并允许循环
  • ICollection包含其他方法:添加,删除,包含,计数,复制到
  • ICollection继承自IEnumerable
  • 使用ICollection,您可以使用添加/删除之类的方法来修改集合。您没有使用IEnumerable进行相同操作的自由。

简单程序:

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("Jack", 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;
        }
    }
}

13

我记得这样:

  1. IEnumerable有一种方法GetEnumerator(),该方法允许读取一个集合中的值,但不能对其进行写入。C#中的for每个语句为我们解决了使用枚举器的大多数复杂问题。IEnumerable具有一个属性:Current,该属性返回当前元素。

  2. ICollection实现IEnumerable,并添加了一些其他属性,其中大多数用途是Count。ICollection的通用版本实现Add()和Remove()方法。

  3. IList同时实现IEnumerable和ICollection,并向项目添加整数索引访问(通常不需要,因为在数据库中进行排序)。


4
根据您写的内容,ICollection和IList是相同的。请添加添加到IList的ICollection中不存在的内容。
下注

ICollection VS IList,System.Collection中仅IList的接口,包含IEnumerable和ICollection的所有功能以及其他功能。IList具有插入和删除方法。两种方法都在其参数中接受索引。因此,它支持对集合的基于索引的操作。
E.Meir '18

7

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


14
TIL ICollection是只读的,而ICollection<T>不是。
卡尔G


2

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


0

让我们尝试通过逻辑思维开箱即用,清楚地了解问题中的这三个接口:

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

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

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

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

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

此接口的通用版本,即System.Collection.Generic.ICollection,更具信息性,因为此通用接口明确声明了集合中事物的类型。

这是所有合理,合理,逻辑的,并且使System.Collections.ICollection接口继承自System.Collections.IEnumerable接口是有意义的,因为从理论上讲每个集合都是可枚举和可迭代的,并且从理论上讲,可以遍历所有项和元素在每个集合中。

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

这解释了为什么System.Collections.ICollection接口具有“添加”和“删除”方法。

由于System.Collections.ICollection接口的实例是有限集合,因此单词“有限”表示该接口的每个集合中始终具有有限数量的项目和元素。

System.Collections.ICollection接口的Count属性假定返回此数字。

System.Collections.IEnumerable接口不具有System.Collections.ICollection接口具有的这些方法和属性,因为System.Collections.IEnumerable将不具有System.Collections.ICollection接口具有的这些方法和属性。

该逻辑还说,每个可枚举和可迭代的实例不一定是集合,也不一定是可更改的。

当我说“可变”时,我的意思是不要立即认为您可以在可枚举和可迭代的事物中添加或删除某些事物。

例如,如果我刚刚创建了一些质数有限序列,那么这个质数有限序列的确是System.Collections.IEnumerable接口的一个实例,因为现在我可以在一个循环中遍历此有限序列中的所有质数并执行我想对它们进行的任何操作,例如将它们打印到控制台窗口或屏幕上,但是这种有限的质数序列不是System.Collections.ICollection接口的实例,因为这对于将复数添加到此有限质数序列中。

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

另外,您可能还想在System.Collections.IEnumerable接口的GetEnumerator方法中使用,编写代码并编写“ yield return”,以产生质数,而不在内存堆上分配任何内容,然后将垃圾回收器(GC)分配给这两者从堆中取消分配并释放该内存,因为这显然既浪费操作系统内存,又降低了性能。

调用System.Collections.ICollection接口的方法和属性时,应在堆上进行动态内存分配和释放,但调用System.Collections.IEnumerable接口的方法和属性时,则不应这样做(尽管System.Collections.IEnumerable接口仅具有1个方法和0个属性)。

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

简而言之,System.Collections.ICollection接口并不意味着它的实例是可排序的,但是System.Collections.IList接口却暗示了这一点。

理论上有序集是无序集的特殊情况。

这也很有意义,并解释了为什么System.Collections.IList接口继承System.Collections.ICollection接口。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.