在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
泛型类的功能 在创建泛型类时,还需要一些其他的C#关键字.例如,不能把null赋予泛型类型.此时,可以使用default关键字.如果泛型类型不需要object类的功能,但需要调用泛型类上的某些特定方法,就可以定义约束. 例如: public class DocumentManager<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; } } } 这是一个使用泛型文档福安里的实例.文档管理器用于从队列中读取文档.先创建一个新的控制台项目DocumentManager,并添加DocumentManager<T>类.AddDocument()方法将一个文档添加到队列中.如果队列不为空,IsDocumentAvailable只读属性就返回true.
默认值 接下来给DocumentManager<T>类添加衣蛾GetDocument()方法. public T GetDocument() { T doc = default(T); lock (this) { doc = documentQueue.Dequeue(); } return doc; } 在这个方法中,应该把类型T指定为null.但是不能把null赋予泛型类型.隐隐是泛型类型也可以实例化为值类型,而null只能用于引用类型.为了解决这个问题,使用了default关键字,通过default关键字,将null赋予引用类型,将0赋予值类型.
default关键字根据上下文可以有多重含义.switch语句使用default定义默认情况,在泛型中,根据泛型类型是引用类型还是值类型,泛型default用于将泛型类型初始化为null或0.
约束 如果泛型类型需要调用泛型类型中的方法,就必须加以约束.对于DocumentManager<T>,文档的所在标题应在DisplayAllDocuments()方法显示.Document类实现带有Title和COntent属性的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<T>类显示文档,可以将类型T强制转换为IDocument接口,以显示标题: public void DisplayAllDocument() { foreach (T doc in documentQueue) { Console.WriteLine(((IDocument)doc).Title); } } 问题是,如果类型T没有实现IDocument接口,这个类型强制转换就会导致一个运行异常.最好给DocumentManager<TDocument>类定义一个约束:TDocument类型必须实现IDocument接口.为了在反省类型的名称中指定该要求,将T改为TDocument.where子句指定了实现IDocument接口的要求. public class DocumentManager<TDocument> where TDocument : IDocument {} 这样就可以编写foreach语句,从而使类型TDocument包含属性TItle. Visual Studio InterlliSense和编译器都会提供这个支持. public void DisplayAllDocument() { foreach (TDocument doc in documentQueue) { Console.WriteLine(doc.Title); } } 在main()方法中,用Document类型实例化Documentmanager <T>类,而Document类型实现了需要IDocument接口.接着添加和显示新文档,检索其中一个文档: static void Main() { var dm= new Documentmanager<Document>(); dm.AddDocument(new Document(“Title A”,”Sample A”)); dm.AddDocument(new Document(“Title B”,”Sample B”));
dm.DisplayAllDocument(); if (dm.IsDocumentAvailable) { Document d=dm.GetDocument(); Console.WriteLine(d.Content); } }
DocumentManager现在可以处理任何实现了IDocument接口的类.
在示例应用程序中,介绍了接口约束.泛型支持集中约束类型,如下表:
只有为默认构造函数定义构造函数约束,不能为其他构造函数定义构造函数约束.
使用泛型类型还可以合并多个约束.where T:IFoo,new()约束和MyClass<T>声明指定,类型T必须实现IFoo接口,且必须有一个默认构造函数. public class MyClass<T> where T:IFoo,new() { //.. } 在C#中,where子句的一个重要限制是,不能定义必须由泛型类型实现的运算符.运算符不鞥在接口中定义.在where子句中,只能定义基类,接口和默认构造函数. 以上案例的完整代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace ConsoleApplication9 { class Program { static void Main(string[] args) { var dm = new DocumentManager<Document>(); dm.AddDocument(new Document("Title A", "Sample A")); dm.AddDocument(new Document("Title B", "Sample B"));
dm.DisplayAllDocument(); if (dm.IsDocumentAvailable) { Document d = dm.GetDocument(); Console.WriteLine(d.Content); } Console.ReadKey(); } } public class DocumentManager<TDocument> where TDocument : IDocument { private readonly Queue<TDocument> documentQueue = new Queue<TDocument>(); public void AddDocument(TDocument doc) { lock (this) { documentQueue.Enqueue(doc); } } public bool IsDocumentAvailable { get { return documentQueue.Count > 0; } } public TDocument GetDocument() { TDocument doc = default(TDocument); lock (this) { doc = documentQueue.Dequeue(); } return doc; } public void DisplayAllDocument() { foreach (TDocument doc in documentQueue) { Console.WriteLine(doc.Title); } } } 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; }
} }
继承 前面创建的LinkedList<T>类实现了IEnumerable<out T>接口: public class LinkedList<T>:IEnumerable<out T> { //... } 泛型类型可以实现泛型接口,也可以派生自一个类.泛型类还可以派生自泛型基类: public class Base<T> { } public class Derived<T>:Base<T> {} 要求是必须重复接口的泛型类型,或者必须制定基类的类型,如: public class Base<T> { } public class Derived<T>:Base<string> {} 于是,派生类可以是泛型类或者非泛型类.例如,可以定义一个抽象的泛型基类,它在派生类中用一个具体的类型实现.这允许对特定类型执行特殊的操作: 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; } } 静态成员 泛型类的静态成员需要特别关注.泛型类的景天成员只能在类的一个实例中共享.看下例,其中StaticDemo<T>类包含静态字段x: public class StaticDemo<T> { public static int x; } 在Main()函数中的代码如下: static void Main(string[] args) { StaticDemo<string>.x = 4; StaticDemo<int>.x = 5; Console.WriteLine(StaticDemo<string>.x); Console.ReadKey(); } 由于同时对一个string类型和一个int类型使用了StaticDemo<T>类,所以存在两组静态类型. |
请发表评论