友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
飞读中文网 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

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

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




使用结构约束,类型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中的许多非泛型接口, 从2。0开始定义了新的泛型版本,例如Iparable:

public interface Iparable



int pareTo(T other);



第5章中的非泛型接口Iparable需要一个对象,Person类的pareTo()方法才能按姓氏给人员排序:

public class Person : Iparable



public int pareTo(object obj)



Person other = obj as Person;

return this。lastnamepareTo(other。lastname);

} 

//。。。

执行泛型版本时,不再需要将object的类型强制转换为Person:

public class Person : Iparable



public int pareTo(Person other)

{ 

return this。lastnamepareTo(other。lastname);



//。。。

9。5  泛型方法

除了定义泛型类之外,还可以定义泛型方法。在泛型方法中,泛型类型用方法声明来定义。

Swap方法把T定义为泛型类型,用于两个参数和一个变量temp:

void Swap(ref T x; ref T y)



   T temp;

   temp = x;

   x = y;

   y = temp;



把泛型类型赋予方法调用,就可以调用泛型方法:

int i = 4;

int j = 5;

Swap(ref i; ref j);

但是,因为C#编译器会通过调用Swap方法来获取参数的类型,所以不需要把泛型类型赋予方法调用。泛型方法可以像非泛型方法那样调用:

int i = 4;

int j = 5;

Swap(ref i; ref j);

下面的例子使用泛型方法累加集合中的所有元素。为了说明泛型方法的功能,下面的Account类包含name和balance:

   public class Account

   {

      private string name;

      public string Name

      {

         get

         {

            return name;

         }

      }

      private decimal balance;

      public decimal Balance

      {

         get

         {

            return balance;

         }

      }

      public Account(string name; Decimal balance)

      {

         this。name = name;

         this。balance = balance;

      }

   }

应累加结余的所有账目操作都添加到List类型的账目列表中:

         List accounts = new List();

         accounts。Add(new Account(〃Christian〃; 1500));

         accounts。Add(new Account(〃Sharon〃; 2200));

         accounts。Add(new Account(〃Katie〃; 1800));

累加所有Account对象的传统方式是用foreach语句迭代所有的Account对象,如下所示。foreach语句使用IEnumerable接口迭代集合的元素,所以AccumulateSimple()方法的参数是IEnumerable类型。这样,AccumulateSimple()方法就可以用于所有实现IEnumerable接口的集合类。在这个方法的实现代码中,直接访问Account对象的Balance属性:

   public static class Algorithm

   {

      public static decimal AccumulateSimple(IEnumerable e)

      {

         decimal sum = 0;

         foreach (Account a in e)

         {

            sum += a。Balance;

         }

         return sum;

      }

   }

Accumulate()方法的调用方式如下:

      decimal amount = Algorithm。AccumulateSimple(accounts);

第一个实现代码的问题是,它只能用于Account对象。使用泛型方法就可以避免这个问题。

Accumulate()方法的第二个版本接受实现了IAccount接口的任意类型。如前面的泛型类所述,泛型类型可以用where子句来限制。这个子句也可以用于泛型方法。Accumulate()方法的参数改为IEnumerable。IEnumerable是IEnumerable接口的泛型版本,由泛型集合类实现。

      public static decimal Accumulate(IEnumerable coll)

            where TAccount : IAccount

      {

         decimal sum = 0;

 

         foreach (TAccount a in coll)

         {

            sum += a。Balance;

         }

         return sum;

      }

Account类现在重构为执行接口IAccount:

public class Account : IAccount



//。。。

IAccount接口定义了只读属性Balance和Name:

public interface IAccount



decimal Balance { get; }

string Name { get; }



将Account类型定义为泛型类型参数,就可以调用新的Accumulate()方法:

      decimal amount = Algorithm。Accumulate(accounts);

因为编译器会从方法的参数类型中自动推断出泛型类型参数,所以以如下方式调用Accumulate()方法是有效的:

      decimal amount = Algorithm。Accumulate(accounts);

泛型类型实现IAccount接口的要求过于严厉。这个要求可以使用泛型委托来改变。在下一节中,Accumulate()方法将改为独立于任何接口。

9。6  泛型委托

如第7章所述,委托是类型安全的方法引用。通过泛型委托,委托的参数可以在以后定义。

 Framework定义了一个泛型委托EventHandler,它的第二个参数是TEventArgs类型,所以不再需要为每个新参数类型定义新委托了。

public sealed delegate void EventHandler(object sender; TEventArgs e)

where TEventArgs : EventArgs
9。6。1  执行委托调用的方法

把Accumulate()方法改为有两个泛型类型。TInput是要累加的对象类型,TSummary是返回类型。Accumulate的第一个参数是IEnumerable接口,这与以前相同。第二个参数需要Action委托引用一个方法,来累加所有的结余。

在实现代码中,现在给每个元素调用Action委托引用的方法,再返回计算的总和:

public delegate TSummary Action(TInput t; TSummary u);

public static TSummary Accumulate(IEnumerable coll;

      Action action)



   TSummary sum = default(TSummary);

   foreach (TInput input in coll)

   {

      sum = action(input; sum);

   }

   return sum;

返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!