65.9K
CodeProject 正在变化。 阅读更多。
Home

List vs IEnumerable vs IQueryable vs ICollection vs IDictionary

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (353投票s)

2019 年 4 月 3 日

CPOL

7分钟阅读

viewsIcon

1132336

downloadIcon

4480

本文是关于数据结构、数组、ArrayList、List、IList、ICollection、Stack、Queue、HashTable、Dictionary、IQueryable、IEnumerable 的最早(提供完整清晰的比较)的资料之一。

Complete Collection Comparison

Collection

集合是相关记录的集合。它包含有意义的单元
我们应该选择合适的容器来临时存储数据,以进行获取和修改过程。
合适的容器取决于

  1. 我们想对数据做什么(仅仅读取,还是进行插入、删除、更新等修改操作)
  2. 需要传输的记录数量

数组

  1. 固定长度 -> 它的长度是不可变的。它在实例化时确定。
  2. 强类型 -> 开发人员在实例化时而不是运行时确定其类型。此功能使运行时运行速度更快,因为它不需要等待类型定义。
  3. 开发人员使用“foreach”关键字来填充数组并遍历数组。

固定长度和强类型消耗的内存更少,因此性能更好。

        //It is obvious that strArray is 
        //1. string   --> Strongly Type 
        //2. Sized=10 --> Fixed Size

        string[] strArray = new string[10];

        for (int i = 0; i < 10; i++)
        {
            if (strArray[i]==null)
            {
                strArray[i] = (i+1).ToString();
            }
        }

        this.ListBoxArray.DataSource = null;
        this.ListBoxArray.Items.Clear();

        this.ListBoxArray.DataSource = strArray;
        this.ListBoxArray.DataBind();

ArrayList

  1. ArrayList 不是固定长度 -> 数据可以增长。一方面,当开发人员不确定 ArrayList 的大小时,这是一个优点;另一方面,它可能需要很长时间来定义大小。
  2. ArrayList 不是强类型 -> 当开发人员不确定输入或输出数据的确切类型定义时,他们需要等到运行时才能显示其类型。它的缺点是在运行时耗费时间,内存需要确定类型定义。
  3. 开发人员使用“foreach”关键字来填充 ArrayList 并遍历 ArrayList。

public class Product
    {
        public Product()
        {
        
        }
        public Product(string Code, string Name)
        {
            _Code = Code;
            _Name = Name;
        }

		    public string _Code {get; set;}
            public string _Name { get; set; }
    }

ArrayList 可以同时接受 string、整数和十进制数。

        //It is NOT obvious that strArrayList is 1. string? int? object? decimal?  --> NOT Strongly Type 
        //                                       2. Sized=10? 20? 100?             -->NOT Fixed Size
        // Namespace: System.Collections

        System.Collections.ArrayList strArrayList = new System.Collections.ArrayList();
        //System.Linq.IQueryable  type of data is not specific runtime deferred support
        strArrayList.Add("Mahsa");  //   "Mahsa": is string
        strArrayList.Add(1);        //        1 : is integer
        strArrayList.Add(0.89);     //      0.89: is decimal  

        this.ListBoxArrayList.DataSource = null;
        this.ListBoxArrayList.Items.Clear();
        this.ListBoxArrayList.DataSource = strArrayList;
        this.ListBoxArrayList.DataBind();

        System.Text.StringBuilder str= new System.Text.StringBuilder();

        foreach (var item in strArrayList)
        {
            str.Append(" , "+item);
        }
        this.lblArrayList.Text = str.ToString();
        
        //Below is old way to fill obj from product, 
        //in Arraylist you need to create more than one instance
        // Product objProduct = new Product();
        // objProduct.Code = "1001";
        // objProduct.Name = "Chair";

        //It is NOT obvious that strArrayList is 
        //1. string? int? object? decimal? OR OBJECT??  --> NOT Strongly Type 
        //2. Sized=10? 20? 100?                         -->NOT Fixed Size
        // Namespace: System.Collections

        System.Collections.ArrayList objArrayList = new System.Collections.ArrayList();

        objArrayList.Add(new Product("1001", "Chair"));
        objArrayList.Add(new Product("1002", "Sofa"));
        objArrayList.Add(new Product("1003", "Carpet"));

        this.DropDownListArrayListObject.DataSource = null;
        this.DropDownListArrayListObject.Items.Clear();
        this.DropDownListArrayListObject.DataSource = objArrayList;

        //* Finding among Object of Array List is difficult, 
        //you have to find your specific item by index
        Product objTemp = (Product)objArrayList[0];
        objArrayList.Remove(objTemp);
        //*
        this.DropDownListArrayListObject.DataTextField = "_Name";
        this.DropDownListArrayListObject.DataValueField = "_Code";
        this.DropDownListArrayListObject.DataBind();
        this.GridViewArrayListObject.DataSource = objArrayList;
        this.GridViewArrayListObject.DataBind();

HashTable

HashTable 是另一种数据结构,它为每个数据部分定义键值。因此,只需通过其键就可以轻松查找数据。它不是强类型且不是固定大小。

        //It is NOT obvious that strArrayList is 
        //1. string? int? object? decimal? OR OBJECT??  --> NOT Strongly Type 
        //2. Sized=10? 20? 100?                         -->NOT Fixed Size
        // Namespace: System.Collections
        //Hashtable solve the problem in Arraylist when we are looking for specific item
        //Hashtable dedicate a key for each item, then finding item is easier and faster 

         System.Collections.Hashtable objHashTable = new System.Collections.Hashtable();
       
         objHashTable.Add("1001","Chair");
         objHashTable.Add("1002", "Sofa");
         objHashTable.Add("1003", "Carpet");

     
        this.DropDownListHashTable.DataSource = null;
        this.DropDownListHashTable.Items.Clear();
        this.DropDownListHashTable.DataSource = objHashTable;
        //* finding item is easier you just need to point to it by call its key 
        objHashTable.Remove("1002");
        //*
        this.DropDownListHashTable.DataTextField = "Value";
        this.DropDownListHashTable.DataValueField = "Key";
        this.DropDownListHashTable.DataBind();

堆栈

我们有不同的数据结构,堆栈是其中之一。Stack 是数据结构的子集。Stack 是一种优先数据结构(如 List 是基于索引的)。Stack 为每个项目定义优先级,这意味着堆栈行为强制其项目以优先顺序放入(推送)堆栈中。因此,堆栈将最后添加的项目放在最上面,这种行为就是“为每个项目定义优先级”。因此,当您要插入项目时,应该将其添加到堆栈的顶部(PUSH);当您要从堆栈中删除项目(POP)时,应该将其从堆栈的顶部删除。如您所知,最后进来的项目将首先被选择弹出,其在计算机科学中的表达等于“后进先出” == “LIFO”。

它不是强类型且不是固定大小。

Stack - Push

        //Stack is LIFO: Last in First Out
        System.Collections.Stack objStackPush = new System.Collections.Stack();

        //By Push method, you can insert item at the top of the stack
        objStackPush.Push("Mahsa");
        objStackPush.Push("Hassankashi");
        this.lblPop.Text = "";
        this.ListBoxStack.DataSource = objStackPush.ToArray();
        this.ListBoxStack.DataBind();

Stack - Pop

        System.Collections.Stack objStackPop = new System.Collections.Stack();

        objStackPop.Push("Mahsa");
        objStackPop.Push("Hassankashi");

        //By Pop method, you can remove item from the top of the stack --> Last in First in 
        this.lblPop.Text = objStackPop.Pop().ToString();

        this.ListBoxStack.DataSource = objStackPop.ToArray();
        this.ListBoxStack.DataBind();

队列

Queue 是另一种数据结构,它以另一种形式为每个项目定义优先级。因此,当您要插入项目时,应该将其添加到队列的头部(Enqueue);当您要从队列中删除项目(Dequeue)时,应该将其从队列的底部删除。如您所知,最先进入的项目将最先被选择出队,其在计算机科学中的表达等于“先进先出” == “FIFO”。

它不是强类型且不是固定大小。

Queue - Enqueue

        //Queue is FIFO: First in First Out
        System.Collections.Queue objQueue = new System.Collections.Queue();

        //By Enqueue method you can insert item at the END of the Queue
        objQueue.Enqueue("Mahsa");
        objQueue.Enqueue("Hassankashi");
        objQueue.Enqueue("Cosmic");
        objQueue.Enqueue("Verse");

        this.lblQueue.Text = "";
        this.ListBoxQueue.DataSource = objQueue.ToArray();
        this.ListBoxQueue.DataBind();

Queue - Dequeue

        System.Collections.Queue objQueue = new System.Collections.Queue();

        objQueue.Enqueue("Mahsa");
        objQueue.Enqueue("Hassankashi");
        objQueue.Enqueue("Cosmic");
        objQueue.Enqueue("Verse");

        //By Dequeue method you can remove item from the BEGINNING of the Queue --> 
        //First in First out FIFO
        this.lblQueue.Text=objQueue.Dequeue().ToString();
       
        this.ListBoxQueue.DataSource = objQueue.ToArray();
        this.ListBoxQueue.DataBind();

列表

为什么我们需要 List

  1. List 不是固定长度 -> 数据可以增长。一方面,当开发人员不确定 ArrayList 的大小时,这是一个优点;另一方面,它可能需要很长时间来定义大小。
  2. List 被定义为“泛型”时,它是强类型的 -> 当开发人员确定输入或输出数据的确切类型定义,并且不等到运行时才显示其类型时。此功能使运行时运行速度更快,因为它不需要等待类型定义。
  3. 开发人员使用“foreach”关键字来填充数组并遍历数组。

由于 List 不是固定长度,这使得开发人员在使用它时感觉灵活,并且因为它在定义为“泛型”时是强类型的,所以我们的代码在运行时运行得很快,因为它不需要等待类型定义。

        //Like Array is Strong Type
        //Like ArrayList with No Dimension
        System.Collections.Generic.List<string> strList = new List<string>();

        strList.Add("Mahsa");
        strList.Add("Hassankashi");
        strList.Add("Cosmic");
        strList.Add("Verse");
       
        this.ListBoxListGeneric.DataSource = strList;
        this.ListBoxListGeneric.DataBind();

        System.Text.StringBuilder str = new System.Text.StringBuilder();

        foreach (var item in strList)
        {
            str.Append(" , " + item);
        }
        this.lblList.Text = str.ToString();

IList

为什么我们需要 IListIListList 实现,IList 是一个接口并实现方法。当您估计代码将来可能会被更改时,您必须使用 IList,因为接口可以减少依赖性,并且只需进行少量修改,您的代码即可运行。因此,您应该观察多态性,以便解耦您的应用程序并控制可能更改的添加或删除方法。其他一切都相似。当我们想要在某个操作上进行更改时,“IList”可以让我们轻松地做到这一点,而无需更改整个代码。

接口不能被实例化,因此应该从 List 实例化。

System.Collections.Generic.IList<string> strIList = new List<string>();

具体类与接口的区别

  1. 具体类只继承自一个类,但可以实现一个或多个接口。
  2. 您可以在具体类中编写函数的完整版本,而必须仅在接口中定义签名。
  3. 您可以在具体类中定义变量和值,而在接口中不允许定义变量。
  4. 具体类可以有构造函数,而在接口中不允许定义构造函数。
  5. 抽象类可以包含访问修饰符,而接口则不能。

正如我所提到的,**类不能从两个类派生**,它只能从一个类派生,所以当您想从两个类派生时,不可能继承两个**抽象**类,但是**可以通过接口从多个类派生**。

将来,如果开发人员决定向其类添加一些功能并将其从另一个类继承,开发人员总是更倾向于使用集合接口,这样,如果您想更改代码并增强其功能,请选择接口。

另一方面,接口使您的程序**可扩展**和**解耦**:类是相互独立的,因此将来更改代码时很少会发生错误、异常和故障。使用接口。

**多态性**:当您使用接口时,您绝对会观察到并实践多态性和面向对象编程。这意味着封装您的设计者。接口意味着一个点或一个节点来连接两个部分,这意味着**低依赖性**地连接两个部分,并创建一个联合部分以便将来进行灵活的更改。

        //Ilist can not be instantiate from Ilist , so it should be instantiate from List
        System.Collections.Generic.IList<string> strIList = new List<string>();

        strIList.Add("Mahsa");
        strIList.Add("Hassankashi");
        strIList.Add("Cosmic");
        strIList.Add("Verse");
        
        this.ListBoxListGeneric.DataSource = strIList;
        this.ListBoxListGeneric.DataBind();

        System.Text.StringBuilder str = new System.Text.StringBuilder();

        foreach (var item in strIList)
        {
            str.Append(" , " + item);
        }
        this.lblList.Text = str.ToString();

IEnumerable

IEnumerable 仅适用于遍历集合,您不能修改(AddRemove)数据。IEnumerable 将所有数据从服务器带到客户端,然后过滤它们,假设您有大量记录,那么 IEnumerable 会给您的内存带来开销。

        //IEnumerable can not be instantiate from Enumerable , so it should be instantiate from List
        System.Collections.Generic.IEnumerable<Employee> empIEnumerable = new List<Employee>
        {   new Employee { ID = 1001, Name="Mahsa"},
            new Employee { ID = 1002, Name = "Hassankashi" },
            new Employee { ID = 1003, Name = "CosmicVerse" },
            new Employee { ID = 1004, Name = "Technical" }
        };

        this.GridViewIEnumerable.DataSource = empIEnumerable;
        this.GridViewIEnumerable.DataBind();

        System.Text.StringBuilder str = new System.Text.StringBuilder();

        foreach (Employee item in empIEnumerable)
        {
            str.Append(" , " + item.ID +"-"+item.Name);
        }

        this.lblIEnumerable.Text = str.ToString();

IQueryable

当我们遇到大量数据记录时,我们必须减少应用程序的开销。IQueryable 在这种情况下(大量数据)通过首先过滤数据,然后将过滤后的数据发送到客户端,从而提供高.性能。

DataAccessEntities ctx = new DataAccessEntities();
        var ctx = new DataAccessEntities();    

        //Difference between IQueryable and IEnumerable
        //You can instantiate IEnumerable from List
        IEnumerable<employee> queryIEnumerable = new List<employee>() ;

        //Bring  ALL records from server --> to client then filter collection
        //To bring all data from server you should omit where clause from linq to sql 
        queryIEnumerable = from m in ctx.Employees select m;

        //If you use where as extension method with IEnumerable then All records will be loaded 
        queryIEnumerable = queryIEnumerable.Where(x => x.ID == 1).ToList();

        //You cannot instantiate IQueryable

        IQueryable<employee> queryIQueryable=null;

        //Bring just ONE record from server --> to client

        queryIQueryable = (from m in ctx.Employees
                     where m.ID == 1
                     select m);

        //Whenever you call IQueryable so ==> It will be executed 
        this.GridViewIQueryable.DataSource = queryIQueryable.ToList();
        this.GridViewIQueryable.DataBind();

SQL Profiler

如何跟踪您的查询生成的 TSQL 和将加载多少条记录

步骤 1

开始 -> MS SQL Server 2008 -> Performance Tools -> SQL Server Profiler

第二步

SQL Server Profiler -> File -> New Trace

步骤 3

使用您的用户名和密码连接。

步骤 4

General (Tab) -> Use the Template: Standard

步骤 5

Event Selection (Tab) -> Event : TSQL -> Select : SQL-BatchCompleted | Select Show all Columns

Press Column Filter -> Database Name: Like: "DataAccess"

Press Run.

步骤 6

转到 MS SQL Server Management Studio -> 计算所有记录(records=5)

步骤 7

IEnumerable 生成
SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[Name] AS [Name], 
[Extent1].[Age] AS [Age]
FROM [dbo].[Employee] AS [Extent1]

IQueryable 生成
SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[Name] AS [Name], 
[Extent1].[Age] AS [Age]
FROM [dbo].[Employee] AS [Extent1]
WHERE 1 = [Extent1].[ID]

ICollection

ICollection 继承自 IEnumerable。有一个区别

您可以找到 IEnumerable[ i ] --> 基于索引

您找不到 ICollection[ i ] --> 非基于索引

        //IList {indexer and Modify} vs ICollection {randomly and Modify}         
        //Collection can not be instantiate from ICollection , so it should be instantiate from List
        System.Collections.Generic.ICollection<string> strICollection = new List<string>();
        strICollection.Add("Mahsa");
        strICollection.Add("Hassankashi");

        //Countable***
        int ICollectionCount=strICollection.Count;

        this.ListBoxICollection.DataSource = strICollection;
        this.ListBoxICollection.DataBind();
        System.Text.StringBuilder str = new System.Text.StringBuilder();
        foreach (var item in strICollection)
        {
            str.Append(" , " + item);
        }
        this.lblICollection.Text = str.ToString();
        
        //IList***
        System.Collections.Generic.IList<Employee> objIList = new List<Employee>();
        objIList = (from m in ctx.Employees
                    select m).ToList();
       
        Employee obj = objIList.Where(i => i.Name == "Sara").FirstOrDefault();
        int indexofSara= objIList.IndexOf(obj);
        int cIList = objIList.Count;

        //ICollection***
        System.Collections.Generic.ICollection<Employee> objICollection = new List<Employee>();
        objICollection = (from m in ctx.Employees
                          select m).ToList();
        Employee objIC = objICollection.Where(i => i.Name == "Sara").FirstOrDefault();
        //You can not get index of object , if you clear comment from below code appears error
        // int indexofSaraICollection = objIC.IndexOf(objIC);
        int cICollection = objICollection.Count;

Stack Generic

推送 (Push)

//Stack is LIFO: Last in First Out
       //Here is for Push Stack in Generic
       //System.Collections.Stack objStackPush = new System.Collections.Stack();
       //Stack<T> can be instantiated from Stack<T>

       System.Collections.Generic.Stack<int> objStackPush = new System.Collections.Generic.Stack<int>();

       objStackPush.Push(1);
       objStackPush.Push(2);

       this.lblPopGeneric.Text = "";
       this.ListBoxStackGeneric.DataSource = objStackPush.ToArray();
       this.ListBoxStackGeneric.DataBind();

Pop

       //Stack is LIFO: Last in First Out
       //Here is for Pop Stack in Generic
       //System.Collections.Stack objStackPop = new System.Collections.Stack();
       //Stack<T> can be instantiated from Stack<T>

       System.Collections.Generic.Stack<int> objStackPop = new System.Collections.Generic.Stack<int>();

       objStackPop.Push(1);
       objStackPop.Push(2);

       this.lblPop.Text = objStackPop.Pop().ToString();
       this.ListBoxStack.DataSource = objStackPop.ToArray();
       this.ListBoxStack.DataBind();

Queue Generic

Enqueue

       //Queue is FIFO: First in First Out
       //Here is for Enqueue Queue in Generic
       //System.Collections.Queue objQueue = new System.Collections.Queue();
       //Queue<T> can be instantiated from Queue<T>

       System.Collections.Generic.Queue<int> objQueue = new System.Collections.Generic.Queue<int>();
       objQueue.Enqueue(1);
       objQueue.Enqueue(2);

       this.lblQueue.Text = "";

       this.ListBoxQueue.DataSource = objQueue.ToArray();
       this.ListBoxQueue.DataBind();

Dequeue

        //Queue is FIFO: First in First Out
        //Here is for Dequeue Queue in Generic
        //System.Collections.Queue objQueue = new System.Collections.Queue();
        //Queue<T> can be instantiated from Queue<T>

        System.Collections.Generic.Queue<int> objQueue = new System.Collections.Generic.Queue<int>();

        objQueue.Enqueue(1);
        objQueue.Enqueue(2);

        this.lblQueue.Text = objQueue.Dequeue().ToString();

        this.ListBoxQueue.DataSource = objQueue.ToArray();
        this.ListBoxQueue.DataBind();

Dictionary and IDictionary

Dictionary 是泛型,而 HashTable 不是泛型:Dictionary<TKey, TValue>。它们之间有一个微小的区别,如果 dictionary 找不到特定的键,它会抛出异常,而 HashTable 只返回 null

IDictionary 是接口,如果您预计将来会有大的更改,请使用 IDictionary 而不是 Dictionary

        //Dictionary can instantiate from Dictionary , Dictionary is similar to Hashtable, 
        //Dictionary is GENERIC but Hashtable is NON GENERIC
        //Such Hashtable you can find object by its key
        System.Collections.Generic.Dictionary<int, 
        string=""> objDictionary = new Dictionary<int, string="">();

        objDictionary.Add(1001, "Mahsa");
        objDictionary.Add(1002, "Hassankashi");
        objDictionary.Add(1003, "Cosmicverse");

        string str = objDictionary[1002];

        this.ListBoxDictionary.DataSource = objDictionary;
        this.ListBoxDictionary.DataBind();</int,></int,>

参考文献

反馈

请随时对本文提供任何反馈;很高兴看到您的评论和投票。如果您有任何问题,请随时在此处提问。

© . All rights reserved.