411

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

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

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

4

9 回答 9

482

通常,您选择什么取决于您需要访问哪些方法。一般来说 - 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)。

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

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

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

于 2012-04-11T20:20:12.267 回答
100

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

于 2012-04-11T20:16:29.070 回答
66

回答您的问题List<T>

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

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

于 2012-04-11T20:35:57.757 回答
31

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

  • IEnumerable - 仅包含 GetEnumerator 方法来获取 Enumerator 并允许循环
  • ICollection包含其他方法:Add、Remove、Contains、Count、CopyTo
  • 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;
        }
    }
}
于 2016-11-02T11:56:37.950 回答
18

我是这样记的:

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

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

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

于 2015-03-15T13:57:53.373 回答
7

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

于 2012-04-11T20:18:27.323 回答
2

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

于 2014-01-24T18:18:19.753 回答
2

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

如果导航属性可以包含多个实体(如在多对多或一对多关系中),则其类型必须是可以添加、删除和更新条目的列表,例如 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-应用程序

于 2016-12-27T00:33:01.370 回答
1

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

当某个实例的类实现了 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 接口。

于 2019-08-10T18:10:38.480 回答