为什么需要泛型:
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 DocumentManagerwhere T :IDocument { private readonly Queue documentQueue = new Queue (); /// /// AddDocument()方法将一个文档添加到 /// 队列中。如果队列不为空,IsDocumentAvailable只读属性就返回 true /// /// public void AddDocument(T doc) { lock (this) { documentQueue.Enqueue(doc); } } ////// 队列中有值返回True否则False /// public bool IsDocumentAvailable { get { return documentQueue.Count > 0; } } ////// 给类型 T指定默认值 /// ///public T GetDocument() { T doc = default(T); //泛型默认值:使用 default 关键字 lock (this) { doc = documentQueue.Dequeue(); } return doc; } /// /// 展示所有文档 /// 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) { //DocumentManagertm = new DocumentManager (); //tm.AddDocument(new TDocument("Title TDocument","Content TDocument")); //tm.DisplayAllDocument(); DocumentManager dm = new DocumentManager (); 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类,所以存在两组静态字段: StaticDemo .x = 1; StaticDemo .x = 11; StaticDemo .x = 111; Console.WriteLine(StaticDemo .x); Console.WriteLine(StaticDemo .x);
public class StaticDemo{ public static int x; }
引自《C#高级编程》