泛型类功能
1.创建一个泛型类
public class DocumentMangereList<T> { private readonly Queue<T> documentQueue = new Queue<T>(); public void AddDocument(T doc) { lock (this) { documentQueue.Enqueue(doc); } } public bool IsDocumentAvailable { get { return documentQueue.Count > 0; } } }
2.默认值
现在DocumentMangereList<T>类添加一个GetDocument()方法。 在这个方法中,应把类型T指定为null。 但是,不能把null赋予泛型类型。原因是泛型类型也可以实例化为值类型,而 null 只能用于引用类型。为了解决这个问题,可以使用 default 关键字。通过 default关键字,将 null赋予引用类型,将 0 赋予值类型。
//默认值 public T GetDocument() { T doc = default(T); lock (this) { doc = documentQueue.Dequeue(); } return doc; }
3.约束
如果泛型类需要调用泛型类型中的方法,就必须添加约束。对于DocumentManagerList,文档的所有标题应在 DisplayAllDocuments()方法中显示。Document类实现带有 Title 和 Content属性的 IDocment接口:
public interface IDocument { string Title { get; set; } string Content { get; set; } } public class Document : IDocument { public Document() { } public Document(string title, string content) { this.Title = title; this.Content = content; } public string Title { get; set; } public string Content { get; set; } }
要使用 DocumentManagerList<T> 类显示文档,可以将类型 T 强制转换为 IDocument接口,以显示标题:
//显示文档 public void DisplayAllDocuments() { foreach (T doc in documentQueue) { Console.WriteLine(((IDocument)doc).Title); } }
问题是,如果类型T没有实现IDocument接口,这个类型强制转换就会导致一个运行异常。最
好给DocumentManagerList<TDocument> 类定义一个约束:TDocument类型必须实现IDocunent接口。为了在泛型类型的名称中指定该要求,将 T改为TDocument。 where子句指定了实现IDocment接口的要求:
public class DocumentMangereList<T> where T:IDocument { //显示文档 public void DisplayAllDocuments() { foreach (T doc in documentQueue) { Console.WriteLine(doc.Title); } } //... }
在Main()方法中,用 Docunent类型实例化DocomentManageList<T>,而Document类型实现了
需要的IDocument接 口。接着添加和显示新文档,检索其中一个文档:
static void Main(string[] args) { var dm = new DocumentMangereList<Document>(); dm.AddDocument(new Document("Title A", "Sanple A")); dm.AddDocument(new Document("Title B", "Sanple B")); dm.DisplayAllDocuments(); if (dm.IsDocumentAvailable) { Document d = dm.GetDocument(); Console.WriteLine(d.Content); } }
输出:
泛型支持几种约束类型
使用泛型类型还可以合并多个约束。where T∶IFoo,new() 约束和 MyClass<T> 声明指定,类型 T 必须实现 IFoo 接口,且必须有一个默认构造函数。
public class MyClass<T> where T: IFoo ,new()
{
//...
}
4.继承
public abstract class Calc<T> { public abstract T Add(T x, T y); public abstract T Sub(T x, T y); } public class IntCalc:Calc<int> { public override int Add(int x, int y) { return x + y; } public override int Sub(int x, int y) { return x - y; } }
5.静态成员
泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享。下面看一个例子,其中 StaticDemo 包含静态字段x:
public class StaticDemo<T> { public static int x; }
由于同时对一个string 类型和一个 int 类型使用了 StaticDemo<T> 类,所以存在两组静态字段:
class Program { static void Main(string[] args) { StaticDemo<string>.x = 4; StaticDemo<int>.x = 5; Console.WriteLine(StaticDemo<string>.x);//输出 4 } }