.NET漫游指南-008-泛型,装箱,泛型委托
来源:互联网 发布:卫生网络答题 编辑:程序博客网 时间:2024/04/30 13:55
概述
这篇主要讨论,泛型的相关概念,什么是泛型,泛型的形式,为什么要用泛型,泛型与类型的装箱有什么优劣,泛型委托的应用,泛型委托的简化编写等内容的较为仔细的浅谈。
CLR 2.0引入了泛型,泛型将类型参数的概念引入.NET,在这之前C#是通过将类型于基类型Object相互强制转化来完成泛化,这就付出了一定的代价,任何类型向上转化成Object时,如果类型为值类型,将他们添加到列表中时必须将其装箱,检索他们时必须取消装箱,无疑这种处理在循环访问大型集合方案时会降低性能。此外编译时缺少类型检查,因此编译时无法检查数据的安全性,只有在运行时才会报错,增加了编码的风险。
泛型类和泛型方法兼具可重用性,类型安全和效率,泛型通常与集合以及作用于集合的方法一起使用。
泛型委托可以自己定义,也可以使用Microsoft内置的泛型委托如:Action,Function等。内置的泛型委托,满足了对泛型委托要求不高的情况下的快速使用。
下面先讲述泛型集合,泛型类,泛型接口,泛型方法,泛型和数组
下面通过对比ArrayList集合类和List集合类来表现泛型的安全性检查的优势。
class ArrayListAndList { System.Collections.ArrayList arrayList = new System.Collections.ArrayList(); public ArrayListAndList() { int i = 0; arrayList.Add(5); arrayList.Add(9); arrayList.Add("异类"); foreach(int item in arrayList) { i += item; } } }
上面的代码编译是可以通过的,虽然第三个add中添加了一个string类型的数据,但是编译器并不会进行检查。但是当代码运行到foreach代码时就会报出“System.InvalidCastException”类型的异常,就是类型转化的异常。
class ArrayListAndList { System.Collections.ArrayList arrayList = new System.Collections.ArrayList(); List<int> list = new List<int>(); public ArrayListAndList() { int i = 0; arrayList.Add(5); arrayList.Add(9); arrayList.Add("异类"); foreach(int item in arrayList) { i += item; } int j = 0; list.Add(5); list.Add(9); list.Add("异类"); foreach(var item in list) { j += item; } } }
List在编码过程中编译器就会报出error CS1503: Argument 1: cannot convert from ‘string’ to ‘int’的错误。
为什么会ArrayList只有在运行的时候会报错,但是List在编译的时候就会报错。
因为在ArrayList中当添加5,9,异类,时已经把数值进行了封箱,当进行foreach循环时将元素拆箱成int型,当拆到“异类”时,拆箱失败,所以就报出了类型转换失败的原因。
ArrayList相对于List来说更为自由,可以创建异类集合,虽然这种集合是可以被程序接受的,甚至于某些情况下要用到这个特性,但是毕竟埋下了类型转化的隐患。
泛型类封装非特定数据类型的操作,但是要注意防止类的过度泛化,泛化虽然提高了代码的灵活性和重用性,但是过度泛化会降低代码的可读性。无限制参数类型的泛化会产生一定的弊端。
泛型类
参考网址:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/generics/generic-classes
首先看泛型类,在创建泛型类的时候需要考虑的几点。
1:将哪些类型泛化为类型参数,保持灵活性和可读性的平衡,避免过度泛化。2:对类型参数采用何种约束机制,原则是在保证可以处理必要数据的情况下采用最大程度的约束(约束机制,参见泛型约束的博文)。
3:是否将泛型分解为基类和子类。
4:是实现一个还是多个泛型接口。
开放结构泛型类:Node<T>
封闭结构泛型类:Node<int>
上面讲述的List<int>
就是一个封闭泛型。
关于其继承性
class BaseNode { }class BaseNodeGeneric<T> { }// concrete typeclass NodeConcrete<T> : BaseNode { }//closed constructed typeclass NodeClosed<T> : BaseNodeGeneric<int> { }//open constructed type class NodeOpen<T> : BaseNodeGeneric<T> { }//No errorclass Node1 : BaseNodeGeneric<int> { }//Generates an error//class Node2 : BaseNodeGeneric<T> {}//Generates an error//class Node3 : T {}class BaseNodeMultiple<T, U> { }//No errorclass Node4<T> : BaseNodeMultiple<T, int> { }//No errorclass Node5<T, U> : BaseNodeMultiple<T, U> { }//Generates an error//class Node6<T> : BaseNodeMultiple<T, U> {}
下面代码是演示泛型类的代码
可以看出:为了可以实现foreach中的迭代,泛型基类GenericList实现了IEnumerable泛型接口
基类GenericList的子类SortedLsit,为了使其参数类型T可以使用compare方法,用IComparable泛型接口对参数类型T进行了泛型约束。然后定义了一个类Person,person类也实现了IComparable接口(这样就可以用SortedList类来进行排序了)。
/********************************* * 该文件是为了帮助理解自定义泛型类 * 首先是定义了自定义的泛型类GenericList,继承了必要的泛型接口,作为基类。 * 然后根据基类GenericList派生出子类SortList,并对类型参数做了约束限制 * 同时创建了一个Person的类,并继承了IComparable接口 * ********************************/ class GenericTest { #region an generic list //creat a generic list class //IEnumerable<T> supports a simple iteration over a collection of a specified type public class GenericList<T> : System.Collections.Generic.IEnumerable<T> { protected Node head; protected Node current = null; protected class Node { public Node next; private T data; //T as a private member datatype public Node(T t) { next = null; data = t; } public Node Next { set { next = value; } get { return next; } } public T Data { set { data = value; } get { return data; } } } public GenericList() { head = null; } //add Node from the head public void AddHead(T t) { Node newNode = new Node(t); newNode.next = head; head = newNode; } public System.Collections.Generic.IEnumerator<T> GetEnumerator() { Node current = head; while (current != null) { yield return current.Data; //yield means the getor is a iterator. current = current.next; } } //return an enumerator that iterates through the collection System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } #endregion #region a SortLsit based on generic list public class SortedList<T>:GenericList<T> where T : System.IComparable<T> { //这个是单链的bubble排序,可以参考数据结构中的排序方法讲解 public void BubbleSort() { if (head == null || head.next == null) return; bool swapped; do { Node previous = null; Node current = head; swapped = false; while(current.next != null) { if (current.Data.CompareTo(current.next.Data) > 0) { Node temp = current.next; current.next = current.next.next; temp.next = current; if(previous == null) { head = temp; } else { previous.next = temp; } previous = temp; swapped = true; } else { previous = current; current = current.next; } } } while (swapped); } } #endregion } public class Person : System.IComparable<Person> { string name; int age; public Person(string s ,int i) { name = s; age = i; } int IComparable<Person>.CompareTo(Person other) { return age - other.age; } public bool Equals(Person other) { return age == other.age; } public override string ToString() { return name + ":" + age; } }
实例化上述类的代码
SortedList<Person> personList = new SortedList<Person>(); string[] names = new string[] { "Jonny", "Kline", "Martin" }; int[] ages = new int[] { 24, 39, 54 }; for(int i = 0; i < 3; i++) { personList.AddHead(new Person(names[i], ages[i])); } //使用IEnumerable接口中的迭代器和IComparable接口中的比较方法 System.Console.WriteLine("unsort"); foreach(var item in personList) { System.Console.WriteLine(item.ToString()); } //实现类中的排序方法 personList.BubbleSort(); System.Console.WriteLine("sorted"); foreach(var item in personList) { System.Console.WriteLine(item.ToString()); } } }
上述代码使用自定义的泛型类实现了对person对象的bubble sort,虽然实现了,但是整体的实现还是较为复杂的,可以参考之前写的一篇002-委托中利用泛型委托来实现bubble sort。两篇文章中的实现有共通之处,但是到项目中具体使用哪一种方式,还是要对比考虑的。
- .NET漫游指南-008-泛型,装箱,泛型委托
- .NET漫游指南-009-泛型事件委托
- .NET漫游指南-002-委托
- .NET漫游指南-003-事件
- .NET漫游指南-005-INotifyProperChanged和List<>,ObservableCollection<>使用
- .NET漫游指南-006-语言集成查询LINQ
- .NET漫游指南-007-WPF中多线程调用界面控件
- 泛型委托(C# 编程指南)
- Unicode漫游指南
- GitHub 漫游指南
- 【GitHub】GitHub 漫游指南
- .NET漫游指南-011-.NET Framework中处理和引发事件
- .NET漫游指南-004-在dataGrid中添加CheckBox支持单选,多选,全选功能
- .NET漫游指南-010-WPF中的KeyDown和PreviewKeyDown事件的区别和用法
- Cocos2d漫游指南第十一章亦真亦幻
- 转 -- Amazon AWS 漫游指南
- .NET程序员面试指南:解释委托的基本原理
- 委托、泛型委托等
- ansible
- 小程序开篇
- go 设置 GOROOT 和 GOPATH
- iOS之利用GCD信号量控制并发网络请求
- Jsp 复习材料一: XML解析
- .NET漫游指南-008-泛型,装箱,泛型委托
- LeetCode-ReversePair
- 手写快速排序
- 46. 主元素
- 字节顺序
- 媒体查询@media
- POJ 2100 Graveyard Design
- POJ 2762【强联通缩点】【拓扑排序】Going from u to v or from v to u?
- 机器学习-导论