泛型类的定义类似于一般的类,只是要使用泛型类型声明。之后就可以在类中把泛型类型用作成员字段,或方法的参数类型。在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 where 关键字指定的。
约束
说明
T:结构
类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。
T:类
类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
T:new()
类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
T:<基类名>
类型参数必须是指定的基类或派生自指定的基类。
T:<接口名称>
类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
T:U
为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。
简单约束说明实例:
// 值类型struct|引用类型class约束
public struct Text
{
}
public class Test <T>
where T : struct
{
//T 在这里是一个值类型
}
public class Check
{
Test <Text > test = new Test <Text >();
}
//new() 约束
public class Text
{
public Text() { }// 无参数的构造函数
}
public class Test <T>
where T : new ()
{
// 可以在其中使用T t = new T();
}
public class Check
{
Test <Text > test = new Test <Text >();
}
// 基类约束
public class Text
{
public void Add() { }
}
public class Test <T>
where T : Text//T 继承至Text
{
// 可以在类型为T的变量上调用Add()方法
}
// 接口约束见下面实例
自定义泛型实例:
// 源代码下载路径:http://media.wiley.com/product_ancillary/41/07645753/DOWNLOAD/Ch10.zip
namespace Wrox.ProCSharp.Generics
{
using System;
using System.Threading;
using System.Collections.Generic;
public interface IDocument
{
string Title { get ;}
string Content { get ;}
}
public class Document : IDocument
{
private string title;
public string Title
{
get { return title; }
}
private string content;
public string Content
{
get { return content; }
}
public Document(string title, string content)
{
this .title = title;
this .content = content;
}
}
/// <summary>
/// 定制泛型类【使用接口约束】
/// </summary>
public class ProcessDocuments <TDocument, TDocumentManager>
where TDocument : IDocument
where TDocumentManager : IDocumentManager <TDocument>
{
public static void Start(TDocumentManager dm)
{
new Thread (new ProcessDocuments <TDocument, TDocumentManager>(dm).Run).Start();
}
protected ProcessDocuments(TDocumentManager dm)
{
// 注意不能把null赋予泛型类型,因为泛型类型也可以是值类型。
// 其中T doc = default(T);//则会将null赋予引用类型,把0赋予值类型。
documentManager = dm;
}
// 使用泛型类型定义成员字段
private TDocumentManager documentManager;
protected void Run()
{
while (true )
{
if (documentManager.IsDocumentAvailable)
{
TDocument doc = documentManager.GetDocument();
Console .WriteLine("Processing document {0}" , doc.Title);
}
Thread .Sleep(20);
}
}
}
/// <summary>
/// 定制泛型接口
/// </summary>
public interface IDocumentManager <T>
{
void AddDocument(T doc);
T GetDocument();
bool IsDocumentAvailable
{
get ;
}
}
/// <summary>
/// 定制泛型类
/// </summary>
public class DocumentManager <T> : IDocumentManager <T>
{
private Queue <T> documentQueue = new Queue <T>();
// 泛型类型作为参数类型
public void AddDocument(T doc)
{
lock (this )
{
documentQueue.Enqueue(doc);
}
}
// 泛型类型作为返回类型
public T GetDocument()
{
T doc;
lock (this )
{
doc = documentQueue.Dequeue();
}
return doc;
}
public bool IsDocumentAvailable
{
get { return (documentQueue.Count > 0) ? true : false ; }
}
}
class Program
{
static void Main(string [] args)
{
DocumentManager <Document > dm = new DocumentManager <Document >();
ProcessDocuments <Document , DocumentManager <Document >>.Start(dm);
for (int i = 0; i < 1000; i++)
{
Document doc = new Document ("title" + i.ToString(), "content" );
dm.AddDocument(doc);
Console .WriteLine("added document {0}" , doc.Title);
Thread .Sleep(10);
}
}
}
}