C#学习笔记—泛型

1、与非泛型容器相比,泛型容器的一些优势如下:A、泛型提供了更好的性能,因为它们不会导致装箱或拆箱的损耗;B、泛型更类型安全,因为他们只包含我们指定的类型。C、泛型大幅减少了构建自定义集合类型的需要,因为基础类库提供了几个预制的容器。

2、只有类、结构、接口和委托可以使用泛型,枚举类型不可以。

3、集合初始化语法。只能对支持Add()方法的类使用集合初始化语法,这是ICollection<T>/ICollection接口决定的。

4、使用List<T>类。List<T>类是System.Collections.Generic命名空间中最常用的类型,因为它可以动态调整内容。

 1         private static void UseGeneric()
2 {
3 //使用集合/对象初始化语法,构建一个Person对象的列表
4 List<Person> people = new List<Person>()
5 {
6 new Person{FirstName="Homer", LastName="Simpson", Age=47},
7 new Person{FirstName="Marge", LastName="Simpson", Age=45},
8 new Person{FirstName="Lisa", LastName="Simpson", Age=9},
9 new Person{FirstName="Bart", LastName="Simpson", Age=8},
10 };
11
12 //打印列表中项的个数
13 Console.WriteLine("Items in list: {0}", people.Count);
14
15 //枚举列表
16 foreach (Person p in people)
17 Console.WriteLine(p);
18
19 //插入一个新Person
20 Console.WriteLine("\n ->Inserting new person.");
21 people.Insert(2, new Person{FirstName="Maggie", LastName="Simpson", Age=2});
22 Console.WriteLine("Items in list: {0}", people.Count);
23
24 //将数据复制到新的数组中
25 Person[] arrayOfPeople = people.ToArray();
26 /* for (int i = 0; i < arrayOfPeople.Length; i++)
27 {
28 Console.WriteLine("First Names: {0}", arrayOfPeople[i].FirstName);
29 }
30 */
31 foreach(Person p in arrayOfPeople)
32 Console.WriteLine("First Names: {0}", p.FirstName);
33 }

5、使用Stack<T>类。Stack<T>类表示以后进先出的方式维护数据的集合。它包含Push()和Pop()方法,可以向栈压入数据或从栈移除数据。可以调用Peek()来显示对象。

 1         static void UseGenericStack()
2 {
3 Stack<Person> stackOfPeople = new Stack<Person>();
4 stackOfPeople.Push(new Person { FirstName = "Homer", LastName = "Simpson", Age = 47 });
5 stackOfPeople.Push(new Person { FirstName = "Marge", LastName = "Simpson", Age = 45 });
6 stackOfPeople.Push(new Person { FirstName = "Lisa", LastName = "Simpson", Age = 9 });
7
8 Console.WriteLine("First Person is:{0}", stackOfPeople.Peek());
9 Console.WriteLine("Popped off {0}", stackOfPeople.Pop());
10
11 Console.WriteLine("\nFirst Person is:{0}", stackOfPeople.Peek());
12 Console.WriteLine("Popped off {0}", stackOfPeople.Pop());
13
14 Console.WriteLine("\nFirst Person is:{0}", stackOfPeople.Peek());
15 Console.WriteLine("Popped off {0}", stackOfPeople.Pop());
16
17 try
18 {
19 Console.WriteLine("\nFirst Person is:{0}", stackOfPeople.Peek());
20 Console.WriteLine("Popped off {0}", stackOfPeople.Pop());
21
22 }
23 catch (InvalidOperationException ex)
24 {
25 Console.WriteLine("\nError! {0}", ex.Message);
26 }
27
28 }

6、使用Queue<T>类。队列是确保以先进先出的方式访问数据的容器。

Dequeue():移除并返回Queue<T>开始处的对象

Enqueue():在Queue<T>的末尾处添加一个对象

Peek():返回Queue<T>开始处的对象,但不移除

 1         static void Main(string[] args)
2 {
3 UseGenericQueue();
4 Console.ReadLine();
5 }
6
7 static void GetCoffee(Person p)
8 {
9 Console.WriteLine("{0} got coffee!", p.FirstName);
10 }
11
12 static void UseGenericQueue()
13 {
14 Queue<Person> peopleQ = new Queue<Person>();
15 peopleQ.Enqueue(new Person { FirstName = "Homer", LastName = "Simpson", Age = 47 });
16 peopleQ.Enqueue(new Person { FirstName = "Marge", LastName = "Simpson", Age = 45 });
17 peopleQ.Enqueue(new Person { FirstName = "Lisa", LastName = "Simpson", Age = 9 });
18
19 Console.WriteLine("{0} is first in line!", peopleQ.Peek().FirstName);
20
21 GetCoffee(peopleQ.Dequeue());
22 GetCoffee(peopleQ.Dequeue());
23 GetCoffee(peopleQ.Dequeue());
24
25 try
26 {
27 GetCoffee(peopleQ.Dequeue());
28 }
29 catch (InvalidOperationException e)
30 {
31 Console.WriteLine(e.Message);
32 }
33
34 }

7、使用SortedSet<T>类。SortedSet<T>类中的项是排序的,在插入和移除项之后,也能自动确保排序正确。不过你必须通知SortedSet<T>类按何种方式进行排序,你可以向其构造函数传递一个实现了IComparer<T>泛型接口的参数。

 1         private static void UseSortedSet()
2 {
3 SortedSet<Person> setOfPeople = new SortedSet<Person>(new SortPeopleByAge())
4 {
5 new Person{FirstName="Homer", LastName="Simpson", Age=47},
6 new Person{FirstName="Marge", LastName="Simpson", Age=45},
7 new Person{FirstName="Lisa", LastName="Simpson", Age=9},
8 new Person{FirstName="Bart", LastName="Simpson", Age=8},
9 };
10
11 foreach (Person p in setOfPeople)
12 {
13 Console.WriteLine(p);
14 }
15 Console.WriteLine();
16
17 setOfPeople.Add(new Person { FirstName = "Saku", LastName = "Jones", Age = 1 });
18 setOfPeople.Add(new Person { FirstName = "Mikko", LastName = "Jones", Age = 32 });
19
20 foreach (Person p in setOfPeople)
21 {
22 Console.WriteLine(p);
23 }
24 }

8、创建自定义泛型方法

如果你创建的方法的重载只是输入参数不同,可以使用泛型。在定义泛型方法时,类型参数在方法名称之后,参数列表之前进行指定。这里的Swap<T>()方法可以操作任意两个<T>类型的参数。该方法的最大优势在于,只需要维护一个Swap<T>()版本,而且它能以类型安全的方式操作任意两个给定参数类型的项。更重要的是,栈数据保留在栈上,堆数据保留在堆上。

1         static void Swap<T>(ref T a, ref T b)
2 {
3 T temp;
4 temp = a;
5 a = b;
6 b = temp;
7 }

9、创建自定义泛型结构和类

 1         public struct Point<T>
2 {
3 //泛型状态数据
4 private T xPos;
5 private T yPos;
6
7 //泛型构造函数
8 public Point(T xVal, T yVal)
9 {
10 xPos = xVal;
11 yPos = yVal;
12 }
13
14 //泛型属性
15 public T X
16 {
17 get { return xPos; }
18 set { xPos = value; }
19 }
20
21 public T Y
22 {
23 get { return yPos; }
24 set { yPos = value; }
25 }
26
27 public override string ToString()
28 {
29 return string.Format("[{0}, {1}]", xPos, yPos);
30 }
31
32 //重置字段为类型参数的默认值
33 public void ResetPoint()
34 {
35 xPos = default(T);
36 yPos = default(T);
37 }
38 }

在引入泛型时,default关键字被赋予了双重身份。除了在switch结构内部使用外,还可用于设置类型参数的默认值。这是非常有用的,因为一个泛型类型预先并不知道实际的占位符,因此无法安全地假设默认值是什么。

10、泛型基类

如果一个非泛型类扩展了一个泛型类,派生类必须指定一个类型参数;如果泛型基类定义了泛型虚方法或抽象方法,派生类型必须使用指定类型参数重写泛型方法;如果派生类型也是泛型,则它能够重用类型占位符。不过拍摄类型必须遵照基类中的任何约束。

11、类型参数的约束: Where关键字




posted @ 2012-03-16 16:44  luffy_chen  阅读(232)  评论(0编辑  收藏  举报