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

第3章

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

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

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




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;



Accumulate方法可以通过匿名方法调用,该匿名方法指定,账目的结余应累加到第二个Action类型的参数中:

      decimal amount = Algorithm。Accumulate(

            accounts;

delegate(Account a; decimal d)

{ return a。Balance + d; });

除了使用匿名方法之外,还可以使用l表达式把它传送给第二个参数:

decimal amount = Algorithm。Accumulate 《 Account; decimal 》 (

accounts; (a; d) = 》 a。Balance + d;);

提示:

匿名方法和l表达式参见第7章。

如果Account结余的累加需要进行多次,就可以把该功能放在一个AccountAdder()方法中:

      static decimal AccountAdder(Account a; decimal d)

      {

         return a。Balance + d;

      }

联合使用AccountAdder方法和Accumulate方法:

      decimal amount = Algorithm。Accumulate(

            accounts; AccountAdder);

Action委托引用的方法可以实现任何逻辑。例如,可以进行乘法操作,而不是加法操作。

Accumulate()方法和AccumulateIf()方法一起使用,会更灵活。在AccumulateIf()中,使用了另一个Predicate类型的参数。Predicate委托引用的方法会检查某个账目是否应累加进去。在foreach语句中,只有谓词match返回true,才会调用action方法:

      public static TSummary AccumulateIf(

            IEnumerable coll;

            Action action;

            Predicate match)

      {

         TSummary sum = default(TSummary);

         foreach (TInput a in coll)

         {

            if (match(a))

            {

               sum = action(a; sum);

            }

         }

         return sum;

      }

调用AccumulateIf()方法可以实现累加和执行谓词。这里按照第二个l表达式的定义a = 》 a。Balance 》 2000,只累加结余大于2000的账目:

decimal amount = Algorithm。AccumulateIf 《 Account; decimal 》 (

accounts; (a; d) = 》 a。Balance + d; a = 》 a。Balance 》 2000);
9。6。2  对Array类使用泛型委托

第5章使用Iparable和Iparer接口,演示了Array类的几个排序技术。从 2。0开始,Array类的一些方法把泛型委托类型用作参数。表9…2列出了这些方法、泛型类型和功能。

表  9…2

方    法


泛型参数类型


说    明

Sort()


int parison(T x; T y)


Sort()方法定义了几个重载版本。其中一个重载版本需要一个parison类型的参数。Sort()使用委托引用的方法对集合中的所有元素排序

ForEach()


void Action(T obj)


ForEach()方法对集合中的每一项调用由Action委托引用的方法

FindAll()

Find()

FindLast()

FindIndex()

FindLastIndex()


bool Predicate(T match)


FindXXX()方法将Predicate委托作为其参数。由委托引用的方法会调用多次,并一个接一个地传送集合中的元素。Find()方法在谓词第一次返回true时停止搜索,并返回这个元素。FindIndex()返回查找到的第一个元素的索引。FindLast()和FindLastIndex()以逆序方式对集合中的元素调用谓词,因此返回最后一项或最后一个索引。FindAll()返回一个新列表,其中包含谓词为true的所有项

ConvertAll()


TOutput Converter(TInput input)


ConvertAll()方法给集合中的每个元素调用Converter《 TInput; TOutput》委托,返回一列转换好的元素

TrueForAll()


bool Predicate(T match)


TrueForAll()方法给每个元素调用谓词委托。如果谓词给每个

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

你可能喜欢的