详解详解c# 泛型类的功能
泛型类的功能
在泛型类中,由于不知道泛型参数T是什么类型,可能是引用类型,也可能是值类型,因此不能将null等赋予泛型类型。
如何对泛型对象赋初值、如何保证泛型的正确性等,以使用泛型文档管理器为例:
文档管理器用于从队列中读写文档。首先创建一个泛型管理器AddDocument()方法添加一个文档到队列
中,IsDocumentAvailabe只读属性指示队列中是否还有文档。
public class DocumentManager
{
private readonly Queue documentQueue = new Queue();
public void AddDocument(T doc)
{
lock (this)
{
documentQueue.Enqueue(doc);
}
}
public bool IsDocumentAvailable
{
get { return documentQueue.Count > 0; }
}
}
1、默认值
、默认值
给DocumentManager类添加一个GetDocument()方法,该方法以返回队列中的一个文档。如果队列中存在文档,则
返回一个文档;如果队列中已没有文档,则返回默认值。但是,对于泛型T,不能将null赋予T的对象,因为无法确定它是引用
类型还是值类型。在C#中,为我们提供了一个default关键字,泛型T的对象赋予默认值,如:引用类型为null、值类型int等为
0……
public T GetDocument()
{
T doc = default(T);
lock (this)
{
if (documentQueue.Count > 0)
{
doc = documentQueue.Dequeue();
}
}
return doc;
}
2、约束、约束
如果泛型类需要调用泛型类型中的方法,那么必须对泛型添加约束。否则,不能确保声明的泛型类型实现了对应的类型,
具有相关方法。创建文档类Document,其实现了接口IDocument:
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; }
}
给泛型文档管理器DocumentManager添加方法DisplayAllDocuments(),使得队列中所有文档的标题能展示出。在展
示文档标题前,将类型T强制转换为IDocumnet接口,以显示标题:
public void DisplayAllDocuments()
{
foreach (T doc in documentQueue)
{
Console.WriteLine((doc as IDocument).Title);//强制转换
}
}
但是,如果类型T没有实现接口IDocument,在对类型进行强制转换时就会出现一个异常。如果对方法添加rty……catch处
理,将非常损耗性能。同样的,即使类型实现了接口IDocument,在进行转换时也会出现性能的损耗。
那么,如果能对泛型TDocument进行约束,使得泛型类型必须实现接口IDocument,则不会出现对类型进行强制转换时的
异常。甚至不需要强制转换,性能也将得到优化。因此,前面的泛型文档管理器改写为(前面的T,改写为TDocument,以此
暗示是文档类型):
public class DocumentManager
where TDocument : IDocument
{
//……
}
对于实现了约束的泛型文档管理器,可以处理任何实现了IDocument接口的类。其DisplayAllDocuments()方法改写为:
public void DisplayAllDocuments()
{
foreach (TDocument doc in documentQueue)
{
Console.WriteLine(doc.Title);
}
}
在其他地方调用时,可以用Document类型实例化泛型类型DocumentManager。因为Document实现了接口
IDocument:
static void Main()
{
var dm = new DocumentManager();
dm.AddDocument(new Document("Title A", "Sample A"));
dm.AddDocument(new Document("Title B", "Sample B"));
dm.DisplayAllDocuments();
if (dm.IsDocumentAvailable)
{
Document d = dm.GetDocument();
Console.WriteLine(d.Content);
}
}
泛型类型支持的几种约束:struct(结构约束,类型T必须是值类型)、class(类约束,类型T必须是引用类型)、
IFoo(类型T必须实现接口IFoo)、new()(构造函数约束,类型T必须有一个无参构造函数)、TOther(类型T派生自
TOther,也称“裸类型约束”)。
泛型约束中:
只能为无参构造函数定义构造约束,不能为有任何参数的构造函数定义构造函数约束。
泛型可以有多个约束。如:public class DocumentManager where TDocument : IDocument,new()。
where不能定义必须由泛型类型实现的运算符
3、继承、继承
泛型类也可以实现继承,如Queue里,继承实现了接口IEnumerable接口。泛型类型可以实现泛型接口,也可以
派生自一个类。泛型类型可以派生自泛型基类:
class Base
{
//...............
}
class Derived:Base
{
//...............
}
派生类可以是泛型类,也可以是非泛型类型:
abstract class Calc
{
public abstract T Add(T x, T y);
public abstract T Sub(T x, T y);
}
class IncCalc: Calc
{
public override int Add(int x, int y)
{
return x + y;
}
public override int Sub(int x, int y)
{
return x - y;
}
}
class DoubleCalc : Calc
{
public override double Add(double x, double y)
{
return x + y;
}
public override double Sub(double x, double y)
{
return x - y;
}
}
4、静态成员
、静态成员
泛型类的静态成员只能在一个实例中共享:
class StaticDemo
{
public static string Type;
}
static void Main()
{
StaticDemo.Type = "int类型";
StaticDemo