背景:                 
[本书目录] [图书首页] [本书讨论区]  
链接地址:http://www.17xie.com/read-58531.html    注册17xie 一起来写书 实现您的出书梦想!

9.6  泛型委托

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

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

public sealed delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)

where TEventArgs : EventArgs

9.6.1  执行委托调用的方法

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

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

      public delegate TSummary Action<TInput, TSummary>(TInput t, TSummary u);

      public static TSummary Accumulate<TInput, TOutput>(IEnumerable<T> coll,

            Action<TInput, TSummary> action)

      {

         TSummary sum = default(TSummary);

         foreach (TInput input in coll)

         {

            sum = action(input, sum);

         }

         return sum;

      }

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

      decimal amount = Accumulate<Account, decimal>(

            accounts, delegate(Account a, decimal d) { return a.Balance + d; });

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

      static decimal AccountAdder(Account a, decimal d)

      {

         return a.Balance + d;

      }

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

      decimal amount = Accumulate<Account, decimal>(

            accounts, AccountAdder);

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

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

      public static TSummary AccumulateIf<TInput, TSummary>(

            IEnumerable<TInput> coll,

            Action<TInput, TSummary> action,

            Predicate<TInput> match)

      {

         TSummary sum = default(TSummary);

         foreach (TInput a in coll)

         {

            if (match(a))

            {

               sum = action(a, sum);

            }

         }

         return sum;

      }

调用AccumulateIf()方法可以实现累加和执行谓词。这里只累加结余大于2000的账目:

         decimal amount = Algorithm.AccumulateIf<Account, decimal>(

            accounts,

            delegate(Account a, decimal d) { return a.Balance + d; },

            delegate(Account a) {return a.Balance > 2000 ? });

9.6.2  对Array类使用泛型委托

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

表  9-2

方    法

泛型参数类型

说    明

Sort()

int Comparison<T>(T x, T y)

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

ForEach()

void Action<T>(T obj)

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

FindAll()

Find()

FindLast()

FindIndex()

FindLastIndex()

bool Predicate<T>(T match)

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

ConvertAll()

TOutput Converter<TInput,

TOutput>(TInput input)

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

TrueForAll()

bool Predicate<T>(T match)

TrueForAll()方法给每个元素调用谓词委托。如果谓词给每个元素都返回true,则TrueForAll()也返回true。如果谓词为一个元素返回了false,TrueForAll()就返回false

下面看看如何使用这些方法。

Sort()方法把这个委托作为参数接受:

public delegate int Comparison<T>(T x, T y);

这样,就可以使用匿名委托传送两个Person对象,给数组排序。对于Person对象数组,参数T是Person类型:

Person[] persons = {

new Person("Emerson", "Fittipaldi"),

new Person("Niki", "Lauda"),

new Person("Ayrton", "Senna"),

new Person("Michael", "Schumacher")

};

Array.Sort(persons,

delegate(Person p1, Person p2)

{

return p1.Firstname.CompareTo(p2.Firstname);

});

Array.ForEach()方法将Action<T>委托作为参数,给数组的每个元素执行操作:

public delegate void Action<T>(T obj);

于是,就可以传送Console.WriteLine方法的地址,将每个人写入控制台。WriteLine()方法的一个重载版本将Object类作为参数类型。由于Person派生于Object,所以它适合于Person数组:

Array.ForEach(persons, Console.WriteLine);

ForEach()语句的结果将persons变量引用的集合中的每个人都写入控制台:

Emerson Fittipaldi

Niki Lauda

Ayrton Senna

Michael Schumacher

如果需要更多的控制,则可以传送一个匿名方法,其参数应匹配委托定义的参数:

Array.ForEach(persons,

delegate (Person p)

{

Console.WriteLine("{0}", p.Lastname);

}); 

下面是写入控制台的姓氏:

Fittipaldi

Lauda

Senna

Schumacher

Array.FindAll()方法需要Predicate<T>委托:

public delegate bool Predicate<T>(T match);

Array.FindAll()方法为数组中的每个元素调用谓词,并返回一个谓词是true的数组。在这个例子中,对于Lastname以字符串"S"开头的所有Person对象,都返回true。

Person[] sPersons = Array.FindAll(persons,

delegate (Person p)

{

return p.Lastname.StartsWith("S");

});

迭代返回的集合sPersons,并写入控制台,结果如下:

Ayrton Senna

Michael Schumacher

Array.ConvertAll()方法使用泛型委托Converter和两个泛型类型。第一个泛型类型TInput是输入参数,第二个泛型类型TOutput是返回类型。

public delegate TOutput Converter<TInput, TOutput>(TInput input);

如果一种类型的数组应转换为另一种类型的数组,就可以使用ConvertAll()方法。下面是一个与Person类无关的Racer类。Person类有Firstname和Lastname属性,而Racer类为赛手的姓名定义了一个属性Name:

public class Racer

{

public Racer(string name)

{

this.name = name;

private string name;

public string Name

{

get { return name; }

set { name = value; }

}

private string team;

public string Team

{

get { return team; }

set { team = value; }

}

}

使用Array.ConvertAll(),很容易将persons数组转换为Racer数组。给每个Person元素调用委托。在每个Person元素的匿名方法的执行代码中,创建了一个新的Racer对象,将firstname和lastname连接起来传送给带一个字符串参数的构造函数。结果是一个Racer对象数组:

Racer[] racers =

Array.ConvertAll<Person, Racer>(

persons,

delegate(Person person)

{

return new Racer(person.Firstname + " " + person.Lastname);

});


字数:7168    最后更新:7个月以前 [04-10 21:32]happyskynet 修改
本页编辑者:happyskynet  
[前一页]:9.5 泛型方法  [后一页]:9.7 Framework的其他…
[在本页中加入书签] [收藏本书] [推荐本书]
  17xie论坛 > 本书讨论区 > 本页评论   (共0条)
发表评论

用户名称 匿名发表
评论内容
验证码

关于我们 | 版权声明 | 免责声明 | 诚聘英才 | 联系我们 | 合作伙伴 | 友情链接 | 广告合作 | 提交意见
Copyright © 2007 17xie.com 互联网协同写书平台 京ICP备08002671号