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

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

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




   {

      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()方法给每个元素调用谓词委托。如果谓词给每个元素都返回true,则TrueForAll()也返回true。如果谓词为一个元素返回了false,TrueForAll()就返回false

 

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

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

public delegate int parison(T x; T y);

这样,就可以使用l表达式传送两个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; (p1; p2)=》 p1。FirstnamepareTo(p2。Firstname));

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

public delegate void Action(T obj);

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

Array。ForEach(persons; Console。WriteLine);

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

Emerson Fittipaldi

Niki Lauda

Ayrton Senna

Michael Schumacher

如果需要更多的控制,则可以传送一个l表达式,其参数应匹配委托定义的参数:

Array。ForEach(persons; p=》 Console。WriteLine(〃{0}〃; p。Lastname));

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

Fittipaldi

Lauda

Senna

Schumacher

Array。FindAll()方法需要Predicate委托:

public delegate bool Predicate(T match);

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

Person'' sPersons = Array。FindAll(persons; p=》 p。Lastname。StartsWith(〃S〃);

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

Ayrton Senna

Michael Schumacher

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

public delegate TOutput Converter(TInput input);

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

public class Racer



public Racer(string name)



this。name = name;

} 

public string Name {get; set}

public string Team {get; set}



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

Racer'' racers =

ArraynvertAll(

persons; p = 》

new Racer(String。Format(〃{0} {1}〃; p。FirstName; p。LastName));

9。7  Framework的其他泛型类型

除了Systemllections。Generic命名空间之外, Framework还有其他泛型类型。这里讨论的结构和委托都位于System命名空间中,用于不同的目的。

本节讨论如下内容:

●       结构Nullable

●       委托EventHandler

●       结构ArraySegment
9。7。1  结构Nullable

数据库中的数字和编程语言中的数字有显著不同的特征,因为数据库中的数字可以为空,C#中的数字不能为空。Int32是一个结构,而结构实现为值类型,所以它不能为空。

只有在数据库中,而且把XML数据映射为类型,才不存在这个问题。

这种区别常常令人很头痛,映射数据也要多做许多工作。一种解决方案是把数据库和XML文件中的数字映射为引用类型,因为引用类型可以为空值。但这也会在运行期间带来额外的系统开销。

使用Nullable结构很容易解决这个问题。在下面的例子中,Nullable用Nullable实例化。变量x现在可以像int那样使用了,进行赋值或使用运算符执行一些计算。这是因为我们转换了Nullable类型的运算符。x还可以是空。可以检查Nullable的HasValue和Value属性,如果该属性有一个值,就可以访问该值:

Nullable x;

x = 4;

x += 3;

if (x。HasValue)



   int y = x。Value;



x = null;

因为可空类型使用得非常频繁,所以C#有一种特殊的语法,用于定义这种类型的变量。定义这类变量时,不使用一般结构的语法,而使用?运算符。在下面的例子中,x1和x2都是可空int类型的实例:

Nullable x1;

int? x2;

可空类型可以与null和数字比较,如上所示。这里,x的值与null比较,如果x不是null,就与小于0的值比较:

int? x = GetNullableType();

if (x  null)



Console。WriteLine(〃x is null〃);



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