集合
集合就如同数组,被用来存储和管理一组具有相同性质的对象。除了基本的数据处理功能,集合还提供了各种数据结构及算法的实现,如队列,链表,排序等,可以轻易地完成复杂的数据操作。集合是一个特殊的类,好比容器一样将一系列相似的项组合在一起,集合中包含的对象称为集合元素。集合可以分为泛型集合类和非泛型集合类两种。泛型集合类一般位于System.Collections.Generic命名空间。非泛型集合类位于System.Collections命名空间,除此之外,在System.Collections.Specialized命名空间中也包含了一些有用的集合类。
System.Collections命名空间
System.Conllections是一个命名空间。包括一组接口和可使用的集合类,这些接口和类定义各种对象(如列表,队列,位数组,哈希表和字典等)的集合。
该命名空间下常用的.NET非泛型集合类如表所示:
类 | 说明 |
ArrayList | 数组集合类,使用大小可按需要动态增加的数组实现IList接口 |
BitArray | 布尔集合类,管理位值的压缩数组,该值表示布尔值,其中true表示位是打开的(1),false表示位是闭合的(0) |
Hashtable | 哈希表,表示键/值对的集合,这些键/值对根据键的哈希代码进行组织 |
Queue | 队列,表示对象的先进先出集合 |
SortedList | 排序集合类,表示键/值对的集合,这些键/值对按键排序并可按照键和索引访问。 |
Stack | 堆栈,表示对象的简单后进先出非泛型集合 |
该命名空间下常用的.NET非泛型集合类的接口如下:
接口 | 说明 |
ICollection | 定义所有非泛型集合的大小,枚举数和同步方法 |
IComparer | 公开一种比较两个对象的方法。 |
IDictionary | 表示键/值对的非通用集合 |
IDictionaryEnumerator | 枚举非泛型字典的元素 |
IEnumerator | 支持对非泛型集合的简单迭代 |
IList | 表示可按照索引单独访问的对象的非泛型集合 |
动态数组ArrayList类
可以将ArrayList类理解为数组类Array的优化版本,该类既有数组的特征,又有集合的特性。
ArrayList是System.Collections命名空间中的类,类似于数组,有人称其为动态数组,其容量可以根据需要自动扩充,元素的索引也可以根据元素数量重新分配,可以动态实现元素的添加,删除等操作。可以将ArrayList类理解为Array的优化版本,该类既有数组的特征,又有集合的特性。
例如,既可以通过下标进行元素访问,对元素排序,搜索,又可以像处理集合一样添加,在指定索引处插入及删除元素。
ArrayList类的几个常用属性
属性名称 | 属性说明 |
Capacity | 获取或设置ArrayList可包含的元素数,默认为4 |
Count | 获取ArrayList中实际包含的元素数 |
Item | 获取或设置指定索引处的元素 |
ArrayList类常用的方法
方法名称 | 方法说明 |
Add | 将元素添加到ArrayList的结尾处 |
AddRange | 在ArrayList的末尾增加一定范围内的元素 |
Clear | 清除ArrayList中所有元素 |
Contains | 检查某元素是否在ArrayList中 |
IndexOf | 返回ArrayList中某个元素值得第一个匹配项对应的索引 |
Insert | 将元素插入ArrayList的指定索引处 |
Remove | 从ArrayList中移除特定元素的第一个匹配项 |
Reverse | 将ArrayList或它的一部分中元素的顺序反转 |
Sort | 对ArrayList或它的一部分中元素进行排序 |
由于ArrayList中元素的类型默认为object,因此在获取集合元素时需要强制进行转换。并且由于object是引用类型,在与值类型进行转换时会引起装箱和拆箱的操作,因此会付出性能的一些代价。
ArrayList类的使用
创建ArrayList
可以使用3种重载构造函数的一种,还可以使用ArrayList的静态方法Repeat创建一个新的ArrayList。这3个构造的声明如下
使用默认的初始化容量创建ArrayList,该实例没有任何元素。格式如下:
public ArrayList();
使用实现了ICollection接口的集合类来初始化新创建的ArrayList。格式如下:
public ArrayList(ICollection C);
指定一个整数值来初始化ArrayList的容量,创建ArrayList,格式如下:
public ArrayList(int capacity)
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ArrayList al1 = new ArrayList(); al1.Add("Hello"); al1.Add("C#"); al1.Add("World!"); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是:{1}",al1.Capacity,al1.Count); ArrayList al2 = new ArrayList(al1); ArrayList al3 = new ArrayList(18); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是{1}",al3.Capacity,al3.Count); ArrayList al4 = ArrayList.Repeat("张三", 3); for (int a = 0; a < al4.Count; a++) { Console.WriteLine(al4[a]); } Console.ReadKey(); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ArrayList al1 = new ArrayList(); al1.Add("Hello"); al1.Add("C#"); al1.Add("World!"); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是:{1}",al1.Capacity,al1.Count); ArrayList al2 = new ArrayList(al1); ArrayList al3 = new ArrayList(18); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是{1}",al3.Capacity,al3.Count); ArrayList al4 = ArrayList.Repeat("张三", 3); for (int a = 0; a < al4.Count; a++) { Console.WriteLine(al4[a]); } Console.ReadKey(); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ArrayList al1 = new ArrayList(); al1.Add("Hello"); al1.Add("C#"); al1.Add("World!"); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是:{1}",al1.Capacity,al1.Count); ArrayList al2 = new ArrayList(al1); ArrayList al3 = new ArrayList(18); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是{1}",al3.Capacity,al3.Count); ArrayList al4 = ArrayList.Repeat("张三", 3); for (int a = 0; a < al4.Count; a++) { Console.WriteLine(al4[a]); } Console.ReadKey(); } } }
运行结果:
向ArrayList中添加元素的方法
1.Add方法将单个元素添加到列表的尾部;AddRange方法获取一个实现ICollection接口的集合实例,例如Array,Queue,Stack等,并将这个集合实例按顺序添加到列表的尾部。
2.也可以使用Insert和InsertRange方法向ArrayList中指定位置插入元素;Insert方法添加单个元素到指定位置,InsertRange从指定的位置开始添加一个实现了ICollection接口的实例。
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ArrayList al1 = new ArrayList(20); al1.Add("我是元素1"); al1.Add("我是元素2"); al1.Add("我是元素3"); string[] str = { "我是元素4","我是元素5","我是元素6"}; al1.AddRange(str); al1.Insert(0, "新增的第一个元素"); ArrayList al2 = new ArrayList(); al2.Add("我是al2新增的第一个元素"); al2.Add("我是al2新增的第二个元素"); al1.InsertRange(2,al2); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是:{1}",al1.Capacity,al1.Count); for (int a = 0; a < al1.Count; a++) { Console.WriteLine(al1[a]); } Console.ReadKey(); } } }
运行结果
删除ArrayList中的元素
ArrayList提供了三种方法可以将指定元素从集合中删除,这三种方法是Remove,RemoveAt和RemoveRange
1.Remove方法接受一个object类型的参数,用于移除指定元素值得第一个匹配集合元素。
2.RemoveAt方法接受一个int类型的参数,用于删除指定索引的集合元素。
3.RemoveRange方法从集合中移除一定范围的元素。
还可以使用Clear方法从ArrayList中移除所有的元素。
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ArrayList al1 = new ArrayList(20); al1.AddRange(new string[6] { "元素1", "元素2", "元素3", "元素4", "元素5", "元素6" }); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是:{1}",al1.Capacity,al1.Count); al1.Remove("元素2"); al1.RemoveAt(2); al1.RemoveRange(0,2); for (int a = 0; a < al1.Count; a++) { Console.WriteLine(al1[a]); } al1.Clear(); Console.ReadKey(); } } }
运行结果为:
排序
可以使用Sort方法对ArrayList集合中的元素进行排序。Sort有3种重载方法。
使用集合元素的比较方式进行排序:
public virtual void Sort();
使用自定义比较器进行排序:
public virtual void Sort(IComparer comparer);
使用自定义比较器进行指定范围的排序:
public virtual void Sort(int index,int count,IComparer comparer);
例如使用集合元素的比较方式进行排序的代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ArrayList al1 = new ArrayList(); al1.AddRange(new string[8] { "Array1", "Array3", "Array6", "Array5", "Array8","Array2","Array7","Array4" }); al1.Sort(); Console.WriteLine("该ArrayList的容量是:{0},元素的个数是:{1}",al1.Capacity,al1.Count); for (int a = 0; a < al1.Count; a++) { Console.WriteLine(al1[a]); } al1.Clear(); Console.ReadKey(); } } }
运行结果:
至于自定义的排序,在后面会提到。
查找ArrayList中的集合元素
在数组列表中查找元素,最常使用的是IndexOf或LastIndexOf方法,另外,还可以使用BinarySearch方法进行搜索。IndexOf方法从前向后搜指定的字符串,如果找到,就返回匹配的第一项的自0开始的索引,否则返回-1,LastIndexOf方法是从后向前搜索指定字符串,如果找到,则返回匹配的最后一项的自0开始的索引,否则返回-1。这两个方法各自有三个重载版本。表示从指定的索引处开始搜索或者是从指定索引处搜索指定长度的字符串。BinarySearch使用二分算法从集合中搜索指定的值,并返回找到的从0开始的索引,否则返回-1。
实例代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { string[] str= { "Array1", "Array2", "Array3", "Array4", "Array5","Array6"}; ArrayList al1 = new ArrayList(str); int i = al1.IndexOf("Array3"); Console.WriteLine("Array3元素在集合中的位置是"+i); i = al1.LastIndexOf("Array5"); Console.WriteLine("Array5元素在集合中的位置是" + i); int j = al1.BinarySearch("Array3"); if (j > 0) { Console.WriteLine("Array3元素在集合中的位置是" + j); } else { Console.WriteLine("没有找到Array3元素" ); } Console.ReadKey(); } } }
ArrayList的遍历
ArrayList内部维护着一个数组,可以通过下标进行访问,而且ArrayList实现了IEnumerable接口,因此要遍历集合,可以使用for和foreach方法
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ArrayList al1 = new ArrayList(new string[5]{"元素1","元素2","元素3","元素4","元素5"}); for (int i = 0; i <al1.Count; i++) { Console.Write(al1[i]); } foreach (object s in al1) { Console.Write(s); } Console.ReadKey(); } } }
例如用ArrayList编写一个管理客户的程序:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class CustomerInfo { private static ArrayList CustomerList = new ArrayList(); private String id; private String name; private String address; public CustomerInfo() { } public CustomerInfo(String myid, String myname, String myaddress) { id = myid; name = myname; address = myaddress; } public String ID { set { id = value; } get { return id; } } public String Name { get { return name; } set { name = value; } } public String Address { get { return address; } set { address = value; } } public static void AddCustomer(CustomerInfo aCustomerInfo) { CustomerList.Add(aCustomerInfo); } public static void Delete(CustomerInfo oo) { int i=CustomerList.IndexOf(oo); if (i < 0) { Console.WriteLine("所要删除对象不存在"); } else { CustomerList.RemoveAt(i); } } public static void Show() { foreach (CustomerInfo s in CustomerList) { Console.WriteLine(s.ID+", "+s.Name+", "+s.Address); } } public static void SortByName() { CustomerList.Sort(new CustomerNameCompare()); } } public class CustomerNameCompare : IComparer { public int Compare(object x, object y) { return new CaseInsensitiveComparer().Compare(((CustomerInfo)y).Name, ((CustomerInfo)x).Name); } } class Program { static void Main(string[] args) { CustomerInfo a1 = new CustomerInfo("ID110","李四","河南郑州市"); CustomerInfo.AddCustomer(a1); CustomerInfo a2 = new CustomerInfo("ID2050","王五","湖南长沙"); CustomerInfo.AddCustomer(a2); CustomerInfo a3 = new CustomerInfo("ID2035","赵三","河南郑州市"); CustomerInfo.AddCustomer(a3); Console.WriteLine("排序前的集合排列"); CustomerInfo.Show(); CustomerInfo.SortByName(); Console.WriteLine("排序后的集合排列"); CustomerInfo.Show(); CustomerInfo a4 = new CustomerInfo("ID0031","赵七","河北石家庄市"); CustomerInfo.AddCustomer(a4); Console.WriteLine("添加一个客户后的所有信息"); CustomerInfo.Show(); CustomerInfo.Delete(a4); Console.WriteLine("删除一个客户对象后的信息"); CustomerInfo.Show(); Console.ReadKey(); } } }
运行结果为:
还可以在CustomerInfo中添加DeleteByName方法,实现按照姓名删除客户对象
public static void DeleteByName(string name) { for (int i = 0; i < CustomerList.Count; i++) { CustomerInfo aa = (CustomerInfo)CustomerList[i]; if (aa.Name == name) { CustomerList.RemoveAt(i); break; } } }
在类CustomerInfo类中添加SortByID方法,实现用ID实现排序。
public static void SortByID() { CustomerList.Sort(new CustomerIDCompare()); }
添加CustomerIDCompare如下面代码:
public class CustomerIDCompare : IComparer { public int Compare(object x, object y) { return new CaseInsensitiveComparer().Compare(((CustomerInfo)x).ID, ((CustomerInfo)y).ID); } }
main方法代码如下:
CustomerInfo a1 = new CustomerInfo("ID110","李四","河南郑州市"); CustomerInfo.AddCustomer(a1); CustomerInfo a2 = new CustomerInfo("ID2050","王五","湖南长沙"); CustomerInfo.AddCustomer(a2); CustomerInfo a3 = new CustomerInfo("ID2035","赵三","河南郑州市"); CustomerInfo.AddCustomer(a3); Console.WriteLine("排序前的集合排列"); CustomerInfo.Show(); CustomerInfo.SortByID(); Console.WriteLine("排序后的集合排列"); CustomerInfo.Show(); CustomerInfo a4 = new CustomerInfo("ID0031","赵七","河北石家庄市"); CustomerInfo.AddCustomer(a4); Console.WriteLine("添加一个客户后的所有信息"); CustomerInfo.Show(); CustomerInfo.DeleteByName("赵三"); Console.WriteLine("删除一个客户对象后的信息"); CustomerInfo.Show(); Console.ReadKey();
HashTable类
HashTable称为哈希表,和ArrayList不同的是它利用键/值来存储数据。在哈希表中,每一个元素都是一个键/值对,并且是一一对应的,通过“键”就可以得到“值”。如果存储电话号码,通常是将姓名和号码存在一起。存储时把姓名当作键,号码当作值,通过姓名即可查到电话号码,这就是一个典型的哈希表存储方式。HashTable是System.Collections命名空间中的一个重要的类,如果把哈希表当作字典,那么“键”就是字典中查的单词,“值”就是关于单词的解释内容。正因为有这个特点,所以有人把哈希表称做“字典”。
在HashTable内部维护着一个哈希表。内部哈希表为插入到其中的每个键进行哈希编码,在后续的检索操作中,通过哈希编码就可以遍历所有元素,这种方法为检索操作提供了较佳的性能。在.NET中键和值可以是任何一种对象,例如字符串,自定义类等。在后台,当插入键值对到HashTable中时,HashTable使用每个键所引用对象的GetHashCode()方法获取一个哈西编码,存入到HashTable中。哈希表常用的属性和方法如表所示:
属性名称 | 属性说明 |
Count | 获取包含在Hashtable中的键/值对的数目 |
Keys | 获取包含在HashTable中的所有键的集合 |
Values |
获取包含在HashTable中的所有值得集合 |
方法名称 | 方法说明 |
Add | 将带有指定键和值的元素添加到HashTable中 |
Clear | 从HashTable中移除所有元素 |
Contains | 确定HashTable是否包含特定键 |
GetEnumerator | 返回IDictionaryEnumerator,可以遍历HashTable |
Remove | 从HashTable中移除带有指定键的元素。 |
HashTable类提供了15个重载的和构造函数,常用的4个HashTable构造函数声明如下:
1.使用默认的初始容量,加载因子,哈希代码,提供程序和比较器来初始化HashTable类的实例。
public HashTable();
2.使用指定容量,默认加载因子,默认哈希代码提供程序和比较器来初始化HashTable类的实例。
public HashTable(int Capacity);
3.使用指定的容量,加载因子来初始化HashTable类的实例。
public HashTable(int capacity,float loadFactor);
4.通过将指定字典中的元素复制到新的HashTable对象中,初始化HashTable类的一个新实例。新HashTable对象的初始化容量等于复制的元素数,并且使用默认的加载因子,哈希代码提供程序和比较器。
public HashTable(IDictionary d);
下面的例子演示如何使用4种方法构建哈希表
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { Hashtable h1 = new Hashtable(); Hashtable h2 = new Hashtable(20);//指定初始容量 Hashtable h3 = new Hashtable(20, 0.8f);//指定初始容量,和加载因子 Hashtable h4 = new Hashtable(h3); Console.ReadKey(); } } }
使用HashTable提供的属性和方法来操作哈希表。例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { Hashtable h1 = new Hashtable(); h1.Add("txt","notepad.exe"); h1.Add("bmp","paint.exe"); h1.Add("dib","paint.exe"); h1.Add("rtf","wordpad.exe"); Console.WriteLine("键=\"rtf\",值={0}",h1["rtf"]); h1["rtf"] = "winword.exe"; Console.WriteLine("键=\"rtf\",值={0}", h1["rtf"]); h1["doc"] = "winword.exe"; if (!h1.ContainsKey("ht")) { h1.Add("ht","hypertrm.exe"); Console.WriteLine("为键ht添加值:{0}",h1["ht"]); } Console.WriteLine("遍历哈希表:"); foreach (DictionaryEntry de in h1) { Console.WriteLine("键={0},值={1}",de.Key,de.Value); } Console.WriteLine("\n删除(\"doc\")"); h1.Remove("doc"); if (!h1.ContainsKey("doc")) { Console.WriteLine("键\"doc\"没有找到"); } Hashtable h2 = new Hashtable(20);//指定初始容量 Hashtable h3 = new Hashtable(20, 0.8f);//指定初始容量,和加载因子 Hashtable h4 = new Hashtable(h3); Console.ReadKey(); } } }
运行结果:
通过键集和值集遍历哈希表中的键或值的方法举例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { Hashtable h1 = new Hashtable(); h1.Add("txt","notepad.exe"); h1.Add("bmp","paint.exe"); h1.Add("dib","paint.exe"); h1.Add("rtf","wordpad.exe"); ICollection valueColl = h1.Values; foreach (string s in valueColl) { Console.WriteLine("值={0}",s); } ICollection keyColl = h1.Keys; foreach (string s in keyColl) { Console.WriteLine("键={0}",s); } Console.ReadKey(); } } }
通用类型————泛型。
.NET提供有功能强大的泛型特性,利用泛型,可以减少代码编写的工作量,提高程序的运行效率。
泛型?什么是泛型,泛型是一种类型占位符,或称之为类型参数。我们知道在一个方法中,一个变量的值可以作为参数,但其实这个变量的本身也可以作为参数,泛型允许我们在调用的时候再指定这个参数是什么类型。泛型就好比Word中的模板,在Word的模板中提供基本的文档编辑内容,在定义Word模板时,对具体编辑哪种类型的文档是未知的。在.NET中泛型则提供了类,结构,接口和方法的模板,与定义Word模板时类似,定义泛型时的具体类型是未知的。在.NET中。泛型能够给我们带来的好处是“类型安全和减少装箱,拆箱”。
例如在ArrayList类中,所有元素类型都为object类型。.NET中的object类是所有类的基类,因此ArrayList类能够接受任何类型的值作为它的元素。当使用ArrayList中的元素时,必须要强制进行类型的转换将元素转换为合适的元素类型。如果元素是值类型的值时,会引起CLR进行拆箱和装箱的操作,造成一定的性能开销,而且,还需要小心处理类型转换中可能出现的错误,但是很多时候我们会把ArrayList集合中的元素定义为确定的类型,或称之为强类型,这样就可以减少性能的开销,而且也避免类型转换中的‘可能会出现的错误,但是如果还需要强类型字符串值,布尔值或其他的类型时,就必须一一地实现这些强类型类,这些重复的工作就会增加代码量,为此我们引入了泛型来处理这种不足,经由指定一个或多个类型占位符,在处理类型操作时,不需要知道集体的类型,而将确定具体类型的工作放在运行时实现。
使用泛型
泛型可以定义泛型类,泛型方法,泛型接口等。在System.Collections.Generic命名空间中包含有几个泛型集合类,List<T>和Dictionary<K,V>是其中非常重要的两种,泛型接口IComparable<T>,ICompaer<T>在实际中也有很重要的作用。
1.泛型集合List<T>和泛型接口ICompaer<T>,IComparable<T>
泛型最重要的应用就是集合操作,使用泛型集合可以提高代码重用性类型安全,并拥有佳的性能。List<T>的用法和ArrayList相似,但是有更好的安全性,无需装箱,拆箱
定义一个List<T>泛型集合的语法如下:
List<T> 集合名=new List<T>();
在泛型的定义中,泛型类型参数"<T>"是必须指定的,其中T是定义泛型类时的占位符,其并不是一种类型,仅代表某种可能的类型。在定义时T会被使用的类型替代,泛型集合List<T>中只能有一个参数类型,"<T>"中的T可以对集合中的元素类型进行约束。
注意:泛型集合必须实例化,实例化时和普通类实例化相同,必须在后面加上“()”;
List<T>的添加,删除和检索等方法和ArrayList相似,但是不需要像ArrayList那样装箱和拆箱。
如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { List<string> Is = new List<string>(); Is.Add("泛型集合元素1"); Is.Add("泛型集合元素2"); Is.Add("泛型集合元素3"); Console.ReadKey(); } } }
泛型接口IComparer<T>,定义了为比较两个对象而实现的方法。定义如下:
public interface IComparer<T> { int Compare(T x, T y); }
类型参数“T”是要比较的对象的类型。Compare方法比较两个对象并返回一个值,指示一个对象是小于,等于还是大于另一个对象。参数x是要比较的第一个对象,y是要比较的第二个对象,均属于T类型,如果返回值大于0,则x>y;如果返回值小于0,则x<y;如果返回值等于0,则x=y。
IComparer<T>泛型接口主要作用是:作为参数传入Sort()方法,实现对象比较方式的排序。
Sort方法的语法如下:
#region 程序集 mscorlib.dll, v4.0.30319 // C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Profile\Client\mscorlib.dll #endregion using System; namespace System.Collections.Generic { // 摘要: // 定义类型为比较两个对象而实现的方法。 // // 类型参数: // T: // 要比较的对象的类型。 public interface IComparer<in T> { // 摘要: // 比较两个对象并返回一个值,指示一个对象是小于、等于还是大于另一个对象。 // // 参数: // x: // 要比较的第一个对象。 // // y: // 要比较的第二个对象。 // // 返回结果: // 一个带符号整数,它指示 x 与 y 的相对值,如下表所示。值含义小于零x 小于 y。零x 等于 y。大于零x 大于 y。 int Compare(T x, T y); } }
public void Sort(IComparer<T> compaer)
使用IComparer<T>接口实现按照客户的姓名进行排序的方法例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class CustomerInfo { private static List<CustomerInfo> CustomerList = new List<CustomerInfo>(); private String id; private String name; private String address; public CustomerInfo() { } public CustomerInfo(String myid, String myname, String myaddress) { id = myid; name = myname; address = myaddress; } public String ID { set { id = value; } get { return id; } } public String Name { get { return name; } set { name = value; } } public String Address { get { return address; } set { address = value; } } public static void AddCustomer(CustomerInfo aCustomerInfo) { CustomerList.Add(aCustomerInfo); } public static void Delete(CustomerInfo oo) { int i = CustomerList.IndexOf(oo); if (i < 0) { Console.WriteLine("所要删除对象不存在"); } else { CustomerList.RemoveAt(i); } } public static void Show() { foreach (CustomerInfo s in CustomerList) { Console.WriteLine(s.ID + ", " + s.Name + ", " + s.Address); } } public static void SortByName() { CustomerList.Sort(new CustomerNameCompare()); } } public class CustomerNameCompare : IComparer<CustomerInfo> { public int Compare(CustomerInfo x, CustomerInfo y) { return (x.Name.CompareTo(y.Name)); } } class Program { static void Main(string[] args) { CustomerInfo a1 = new CustomerInfo("ID110", "李四", "河南郑州市"); CustomerInfo.AddCustomer(a1); CustomerInfo a2 = new CustomerInfo("ID2050", "王五", "湖南长沙"); CustomerInfo.AddCustomer(a2); CustomerInfo a3 = new CustomerInfo("ID2035", "赵三", "河南郑州市"); CustomerInfo.AddCustomer(a3); Console.WriteLine("排序前的集合排列"); CustomerInfo.Show(); CustomerInfo.SortByName(); Console.WriteLine("排序后的集合排列"); CustomerInfo.Show(); CustomerInfo a4 = new CustomerInfo("ID0031", "赵七", "河北石家庄市"); CustomerInfo.AddCustomer(a4); Console.WriteLine("添加一个客户后的所有信息"); CustomerInfo.Show(); CustomerInfo.Delete(a4); Console.WriteLine("删除一个客户对象后的信息"); CustomerInfo.Show(); Console.ReadKey(); } } }
使用IComparable<T>实现比较对象大小的功能。
IComparable<T>是常用的泛型接口。泛型接口也具有一般接口的共同特点,即在接口中可以包含字段,属性,方法和索引器,但都不能够实现。泛型接口IComparable<T>的功能和接口IComparable相似,规定了一个没有实现的方法Compare(Object obj)语法如下:
#region 程序集 mscorlib.dll, v4.0.30319 // C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Profile\Client\mscorlib.dll #endregion using System.Runtime.InteropServices; namespace System { // 摘要: // 定义一种特定于类型的通用比较方法,值类型或类通过实现此方法对其实例进行排序。 [ComVisible(true)] public interface IComparable { // 摘要: // 将当前实例与同一类型的另一个对象进行比较,并返回一个整数,该整数指示当前实例在排序顺序中的位置是位于另一个对象之前、之后还是与其位置相同。 // // 参数: // obj: // 与此实例进行比较的对象。 // // 返回结果: // 一个值,指示要比较的对象的相对顺序。返回值的含义如下:值含义小于零此实例小于 obj。零此实例等于 obj。大于零此实例大于 obj。 // // 异常: // System.ArgumentException: // obj 不具有与此实例相同的类型。 int CompareTo(object obj); } }
此接口中的CompareTo用于比较对象的大小。如果一个类实现了该接口中的这个方法,说明这个类的对象是可以比较大小的。如果当前对象小于obj,返回值小于0;如果当前对象大于obj,返回值大于0;如果当前对象等于obj返回值等于0。
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleApplication2 { class CustomerInfo : IComparable<CustomerInfo> { private String id; private String name; private String address; public CustomerInfo() { } public CustomerInfo(String myid, String myname, String myaddress) { id = myid; name = myname; address = myaddress; } public String ID { get { return id; } set { id = value; } } public String Name { get { return name; } set { name = value; } } public String Address { get { return address; } set { address = value; } } public int CompareTo(CustomerInfo objss) { return this.Name.CompareTo(objss.Name); } } class Program { static void Main(string[] args) { CustomerInfo a1 = new CustomerInfo("id0001","李四","河南郑州市"); CustomerInfo a2 = new CustomerInfo("id0002","王五","湖南长沙市"); if (a1.CompareTo(a2) > 0) { Console.WriteLine("{0}的姓名比{1}的姓名靠前", a1.Name, a2.Name); } else { Console.WriteLine("{0}的姓名比{1}的姓名靠后", a1.Name, a2.Name); } Console.ReadKey(); } } }
运行结果:
提示:在Compare方法中降序排序使用y.CompareTo(x)写法,升序排序使用x.CompareTo(y)写法实现。
泛型集合Dictionary<K,V>
在System.Collections.Generic命名空间,与HashTable相对应的泛型集合是Dictionary<K,V>,其存储数据的方式和哈希表相似,通过键/值来保存元素,并具有泛型的全部特征,编译时检查类型约束,读取时无需进行类型转换。定义Dictionary<K,V>泛型集合中的方法如下:
Dictionary<k,V>泛型集合名=new Dictionary<K,v>();
其中K为占位符,具体的定义时用存储键“Key”的数据类型代替,“V”同样也是占位符,用元素的值“value”的数据类型代替,这样就在定义该集合时,声明了存储元素的键和值的数据类型,保证了类型的安全。
Dictionary<string, string> op = new Dictionary<string, string>(); Dictionary<string, int> op1 = new Dictionary<string, int>();
在这个Dictionary<K,V>的生命中,"<string,string>(<string,int>)"中的第一个string表示集合中Key的类型,第二个string表示Value的类型。
Dictionary<string, string> op = new Dictionary<string, string>(); Dictionary<string, int> op1 = new Dictionary<string, int>(); op.Add("txt","notepad.exe"); op.Add("bmp","paint.exe"); op1.Add("naem", 12); op1.Add("age",20);
使用泛型的好处:
1.性能高。使用泛型不需要进行类型转换,可以避免装箱和拆箱,能提高性能。
2.类型安全。泛型集合对其存储对象进行了类型的约束,不是定义时声明的类型,是无法存储到泛型集合中的,从而保证了数据的类型安全。
3.代码重用。使用泛型可以最大限度地重用代码,保护类型的安全以及提高性能。
在处理集合类时,如果你遇到下列情况,可以考虑使用泛型:
1.如需要对多种类型进行相同的操作处理。
2.如需要处理值类型,使用泛型则可以避免装箱和拆箱带来的性能开销。
3.使用泛型可以在应用程序编译时发现类型错误,增强程序的健壮性。
4.减少不必要的重复编码,是代码结构更加清晰。