List vs IEnumerable vs IQueryable vs ICollection vs IDictionary






4.89/5 (353投票s)
本文是关于数据结构、数组、ArrayList、List、IList、ICollection、Stack、Queue、HashTable、Dictionary、IQueryable、IEnumerable 的最早(提供完整清晰的比较)的资料之一。
Collection
集合是相关记录的集合。它包含有意义的单元
我们应该选择合适的容器来临时存储数据,以进行获取和修改过程。
合适的容器取决于
- 我们想对数据做什么(仅仅读取,还是进行插入、删除、更新等修改操作)
- 需要传输的记录数量
数组
- 固定长度 -> 它的长度是不可变的。它在实例化时确定。
- 强类型 -> 开发人员在实例化时而不是运行时确定其类型。此功能使运行时运行速度更快,因为它不需要等待类型定义。
- 开发人员使用“
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
ArrayList
不是固定长度 -> 数据可以增长。一方面,当开发人员不确定ArrayList
的大小时,这是一个优点;另一方面,它可能需要很长时间来定义大小。ArrayList
不是强类型 -> 当开发人员不确定输入或输出数据的确切类型定义时,他们需要等到运行时才能显示其类型。它的缺点是在运行时耗费时间,内存需要确定类型定义。- 开发人员使用“
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
?
List
不是固定长度 -> 数据可以增长。一方面,当开发人员不确定 ArrayList 的大小时,这是一个优点;另一方面,它可能需要很长时间来定义大小。- 当
List
被定义为“泛型”时,它是强类型的 -> 当开发人员确定输入或输出数据的确切类型定义,并且不等到运行时才显示其类型时。此功能使运行时运行速度更快,因为它不需要等待类型定义。 - 开发人员使用“
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
为什么我们需要 IList
? IList
由 List
实现,IList
是一个接口并实现方法。当您估计代码将来可能会被更改时,您必须使用 IList
,因为接口可以减少依赖性,并且只需进行少量修改,您的代码即可运行。因此,您应该观察多态性,以便解耦您的应用程序并控制可能更改的添加或删除方法。其他一切都相似。当我们想要在某个操作上进行更改时,“IList
”可以让我们轻松地做到这一点,而无需更改整个代码。
接口不能被实例化,因此应该从 List
实例化。
System.Collections.Generic.IList<string> strIList = new List<string>();
具体类与接口的区别
- 具体类只继承自一个类,但可以实现一个或多个接口。
- 您可以在具体类中编写函数的完整版本,而必须仅在接口中定义签名。
- 您可以在具体类中定义变量和值,而在接口中不允许定义变量。
- 具体类可以有构造函数,而在接口中不允许定义构造函数。
- 抽象类可以包含访问修饰符,而接口则不能。
正如我所提到的,**类不能从两个类派生**,它只能从一个类派生,所以当您想从两个类派生时,不可能继承两个**抽象**类,但是**可以通过接口从多个类派生**。
将来,如果开发人员决定向其类添加一些功能并将其从另一个类继承,开发人员总是更倾向于使用集合接口,这样,如果您想更改代码并增强其功能,请选择接口。
另一方面,接口使您的程序**可扩展**和**解耦**:类是相互独立的,因此将来更改代码时很少会发生错误、异常和故障。使用接口。
**多态性**:当您使用接口时,您绝对会观察到并实践多态性和面向对象编程。这意味着封装您的设计者。接口意味着一个点或一个节点来连接两个部分,这意味着**低依赖性**地连接两个部分,并创建一个联合部分以便将来进行灵活的更改。
//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
仅适用于遍历集合,您不能修改(Add
或 Remove
)数据。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,>
参考文献
- msdn.microsoft.com: Commonly Used Collection Types
- https://codeproject.org.cn/Articles/732425/IEnumerable-Vs-IQueryable
- http://www.dotnet-tricks.com/Tutorial/linq/I8SY160612-IEnumerable-VS-IQueryable.html
- http://www.claudiobernasconi.ch/2013/07/22/when-to-use-ienumerable-icollection-ilist-and-list
- http://www.dotnetperls.com/
反馈
请随时对本文提供任何反馈;很高兴看到您的评论和投票。如果您有任何问题,请随时在此处提问。