贝壳电子书 > 电脑IT电子书 > c#高级编程(第6版)--第九章 >

第2章

c#高级编程(第6版)--第九章-第2章

小说: c#高级编程(第6版)--第九章 字数: 每页4000字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!





public class LinkedListNode



private T value;

public LinkedListNode(T value)



this。value = value;



public T Value



get { return value; }



private LinkedListNode next;

public LinkedListNode Next



get { return next; }

internal set { next = value; }



private LinkedListNode prev;

public LinkedListNode Prev



get { return prev; }

internal set { prev = value; }





下面的代码把LinkedList类也改为泛型类。LinkedList包含LinkedListNode元素。LinkedList中的类型T定义了类型T的包含字段first和last。AddLast()方法现在接受类型T的参数,实例化LinkedListNode类型的对象。

IEnumerable接口也有一个泛型版本IEnumerable。IEnumerable派生于IEnumerable,添加了返回IEnumerator的GetEnumerator()方法,LinkedList执行泛型接口IEnumerable。

提示:

枚举、接口IEnumerable和IEnumerator详见第5章。

public class LinkedList : IEnumerable



private LinkedListNode first;

public LinkedListNode First



get { return first; }



private LinkedListNode last;

public LinkedListNode Last



get { return last; }



public LinkedListNode AddLast(T node)



LinkedListNode newNode = new LinkedListNode(node);

if (first  null)



first = newNode;

last = first;



else



last。Next = newNode;

last = newNode;



return newNode;



public IEnumerator GetEnumerator()



LinkedListNode current = first;

while (current != null)



yield return current。Value;

current = current。Next;





IEnumerator IEnumerable。GetEnumerator()



return GetEnumerator();





使用泛型类LinkedList,可以用int类型实例化它,且无需装箱操作。如果不使用AddLast()方法传送int,就会出现一个编译错误。使用泛型IEnumerable,foreach语句也是类型安全的,如果foreach语句中的变量不是int,也会出现一个编译错误。

LinkedList list2 = new LinkedList();

list2。AddLast(1);

list2。AddLast(3);

list2。AddLast(5);

foreach (int i in list2)



Console。WriteLine(i);



同样,可以给泛型LinkedList使用string类型,将字符串传送给AddLast()方法。

LinkedList list3 = new LinkedList();

list3。AddLast(〃2〃);

list3。AddLast(〃four〃);

list3。AddLast(〃foo〃);

foreach (string s in list3)



Console。WriteLine(s);



提示:

每个处理对象类型的类都可以有泛型实现方式。另外,如果类使用了继承,泛型非常有助于去除类型转换操作。

9。3  泛型类的特性

在创建泛型类时,需要一些其他C#关键字。例如,不能把null赋予泛型类型。此时,可以使用default关键字。如果泛型类型不需要Object类的功能,但需要调用泛型类上的某些特定方法,就可以定义约束。

本节讨论如下主题:

●       默认值

●       约束

●       继承

●       静态成员

下面开始一个使用泛型文档管理器的示例。文档管理器用于从队列中读写文档。先创建一个新的控制台项目DocumentManager,添加类DocumentManager。AddDocument()方法将一个文档添加到队列中。如果队列不为空,IsDocumentAvailable只读属性就返回true。

using System;

using Systemllections。Generic;

namespace Wrox。ProCSharp。Generics



public class DocumentManager



private readonly Queue documentQueue = new Queue();

public void AddDocument(T doc)



lock (this)



documentQueue。Enqueue(doc);





public bool IsDocumentAvailable



get { return documentQueueunt 》 0; }






9。3。1  默认值

现在给DocumentManager类添加一个GetDocument()方法。在这个方法中,给类型T指定null。但是,不能把null赋予泛型类型。原因是泛型类型也可以实例化为值类型,而null只能用于引用类型。为了解决这个问题,可以使用default关键字。通过default关键字,将null赋予引用类型,将0赋予值类型。

public T GetDocument()



T doc = default(T);

lock (this)



doc = documentQueue。Dequeue();



return doc;



注意:

default关键字根据上下文可以有多种含义。switch语句使用default定义默认情况。在泛型中,根据泛型类型是引用类型还是值类型,default关键字用于将泛型类型初始化为null或0。
9。3。2  约束

如果泛型类需要调用泛型类型上的方法,就必须添加约束。对于DocumentManager,文档的标题应在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;

thisntent = content;



public string Title { get; set; }

public string Content { get; set; }



要使用DocumentManager类显示文档,可以将类型T强制转换为IDocument接口,以显示标题:

public void DisplayAllDocuments()



foreach (T doc in documentQueue)



Console。WriteLine((IDocument)doc)。Title);





问题是,如果类型T没有执行IDocument接口,这个类型转换就会生成一个运行异常。最好给DocumentManager类定义一个约束:TDocument类型必须执行IDocument接口。为了在泛型类型的名称中指定该要求,将T改为TDocument。where子句指定了执行IDocument接口的要求。

public class DocumentManager

where TDocument : IDocument



这样,就可以编写foreach语句,让类型T包含属性Title了。Visual Studio IntelliSense和编译器都会提供这个支持。

public void DisplayAllDocuments()



foreach (TDocument doc in documentQueue)



Console。WriteLine(doc。Title);





在Main()方法中,DocumentManager类用Document类型实例化,而Document类型执行了需要的IDocument接口。接着添加和显示新文档,检索其中一个文档:

static void Main()



DocumentManager 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(dntent);





DocumentManager现在可以处理任何执行了IDocument接口的类。

在示例应用程序中,介绍了接口约束。泛型还有几种约束类型,如表9…1所示。

 

表  9…1

约    束


说    明

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。该约束也称为裸类型约束

注意:

在CLR 2。0中,只能为默认构造函数定义约束,不能为其他构造函数定义约束。

使用泛型类型还可以合并多个约束。where T : IFoo,new()约束和MyClass声明指定,类型T必须执行IFoo接口,且必须有一个默认构造函数。

public class MyClass

where T : IFoo; new()



//。。。

提示:

在C#中,where子句的一个重要限制是,不能定义必须由泛型类型执行的运算符。运算符不能在接口中定义。在where子句中,只能定义基类、接口和默认构造函数。
9。3。3  继承

前面创建的LinkedList类执行了IEnumerable接口:

public class LinkedList : IEnumerable



//。。。

泛型类型可以执行泛型接口,也可以派生于一个类。泛型类可以派生于泛型基类:

public class Base





public class Derived : Base





其要求是必须重复接口的泛型类型,或者必须指定基类的类型,如下所示:

public class Base





public class Derived : Base





于是,派生类可以是泛型类或非泛型类。例如,可以定义一个抽象的泛型基类,它在派生类中用一个具体的类型实现。这允许对特定类型执行特殊的操作:

public abstract class Calc



public abstract T Add(T x; T y);

public abstract T Sub(T x; T y);



public class SimpleCalc : Calc



public override int Add(int x; int y)



return x + y;



public override int Sub(int x; int y)



return x … y;




9。3。4  静态成员

泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享。下面看一个例子。StaticDemo类包含静态字段x:

public class StaticDemo



public static int x;



由于对一个string类型和一个int类型使用了StaticDemo类,所以存在两组静态字段:

StaticDemo。x = 4;

StaticDemo。x = 5;

Console。WriteLine(StaticDemo。x); // writes 4

9。4  泛型接口

使用泛型可以定义接口,接口中的方法可以带泛型参数。在链表示例中,就执行了IEnumerable接口,它定义了GetEnumerator()方法,以返回IEnumerator。对于 1。0

返回目录 上一页 下一页 回到顶部 0 0

你可能喜欢的