为什么需要泛型:
CLR 2.0的一个新特性是泛型。在.CLR 1.0 中,要创建一个灵活的类或方法,但该类或方法在编译期间不知道使用什么类,就必须以 Object 类为基础。而 Object 类在编译期间没有类型安全性,因此必须进行强制类型转换。另外,给值类型使用Object类会有性能损失。
性能
第一、泛型的一个主要优点是性能.避免装箱,拆箱
例如:ArrayList方法Add(Value),value值只要继承object均可以添加进去,但是需要:装箱 ;foreach时需要拆箱
(从值类型转换为引用类型称为装箱反之称拆箱)
第二、类型安全
例如:List<T>中,泛型类型 T若 定义了允许使用的类型int,那么Add(value)方法中value只允许int值类型
第三、二进制代码重用(泛型类可以定义一次,用许多不同的类型实例化)
例如:List<int> list = new List<int>(); list.Add(1);
List<string> stringList = new List<string>(); stringList.Add("string");
泛型类型可以在一种语言中定义,在另一种.NET语言中使用。
案例:
DocumentManager
/* * 说明:使用泛型文档管理器的示例 * * 注意: * default关键字根据上下文可以有多种含义。switch语句使用 default定义默认情况。在泛型中,根 * 据泛型类型是引用类型还是值类型,default关键字用于将泛型类型初始化为 null或 0。 * * 创建:2012-04-26 */ using System; using System.Collections.Generic; using System.Text; using System.Collections; namespace DocumentManager { //类约束指定,类型 T必须执行接口IDocument public class DocumentManager<T> where T :IDocument { private readonly Queue<T> documentQueue = new Queue<T>(); /// <summary> /// AddDocument()方法将一个文档添加到 /// 队列中。如果队列不为空,IsDocumentAvailable只读属性就返回 true /// </summary> /// <param name="doc"></param> public void AddDocument(T doc) { lock (this) { documentQueue.Enqueue(doc); } } /// <summary> /// 队列中有值返回True否则False /// </summary> public bool IsDocumentAvailable { get { return documentQueue.Count > 0; } } /// <summary> /// 给类型 T指定默认值 /// </summary> /// <returns></returns> public T GetDocument() { T doc = default(T); //泛型默认值:使用 default 关键字 lock (this) { doc = documentQueue.Dequeue(); } return doc; } /// <summary> /// 展示所有文档 /// </summary> public void DisplayAllDocument() { foreach (T doc in documentQueue) { Console.WriteLine(((IDocument)doc).Title); } } } }
Document
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DocumentManager { public class Document : IDocument { public Document() { } public string Title { get; set; } public string Content { get; set; } public Document(string title, string content) { this.Title = title; this.Content = content; } } }
TDocument
namespace DocumentManager { public class TDocument : IDocument { public TDocument() { } public string Title { get; set; } public string Content { get; set; } public TDocument(string title, string content) { this.Title = title; this.Content = content; } } }
/* * 如果泛型类需要调用泛型类型上的方法,就必须添加约束 * */ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DocumentManager { public interface IDocument { string Title { get; set; } string Content { get; set; } } }
Program
class Program { static void Main(string[] args) { //DocumentManager<TDocument> tm = new DocumentManager<TDocument>(); //tm.AddDocument(new TDocument("Title TDocument","Content TDocument")); //tm.DisplayAllDocument(); DocumentManager<Document> dm = new DocumentManager<Document>(); dm.AddDocument(new Document("Title A", "Sample A")); dm.DisplayAllDocument(); dm.AddDocument(new Document("Title B", "Sample B")); dm.DisplayAllDocument(); if (dm.IsDocumentAvailable) { Document d = dm.GetDocument(); Console.WriteLine(d.Content); } } }
结果:建议先自己心算下……
(是不是和你的意愿不一致?那再好好看看代码)
注意:
default关键字根据上下文可以有多种含义。switch语句使用 default定义默认情况。在泛型中,根
据泛型类型是引用类型还是值类型,default关键字用于将泛型类型初始化为 null或 0。
如果泛型类需要调用泛型类型上的方法,就必须添加约束 。格式: where+约束类型
约 束 | 说 明 |
where T : struct | 使用结构约束,类型 T必须是值类型 |
where T : class | 类约束指定,类型 T必须是引用类型 |
where T : IFoo | 指定类型T必须执行接口 IFoo |
where T : Foo | 指定类型T必须派生于基类 Foo |
where T : new() | 这是一个构造函数约束,指定类型 T必须有一个默认构造函数 |
where T : U |
这个约束也可以指定,类型 T1 派生于泛型类型 T2。该约束也称为裸类型约 |
在where子句中,只能定义基类、接口和默认构造函数。
静态成员
泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享
//泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享 //由于对一个string类型和一个int类型使用了 StaticDemo<T>类,所以存在两组静态字段: StaticDemo<int>.x = 1; StaticDemo<string>.x = 11; StaticDemo<char>.x = 111; Console.WriteLine(StaticDemo<string>.x); Console.WriteLine(StaticDemo<int>.x);
public class StaticDemo<T> { public static int x; }
引自《C#高级编程》