.NET/C#中对对象集合进行查询的方法 以及相关的 Predicate<T> 及 Action<T> 的用法

原文地址:http://www.cnblogs.com/csharp4/archive/2010/06/08/1754266.html


所谓的对对象集合进行查询的方法,就是指,如何从一个集合中找出符合条件的某些项来。这一次我没有用 自定义对象集合,而是直接使用对象集合,是因为普通的对象集合,如int[], List<int>,这样的东西,也没有统一固定的查询方法,因为对于一个查询来讲,它的条件是多种多样的,所以是无法提供统一固定查询方法的。比如有时候想找出所有大于10的int,有时候又想找所有小于10的int。。。。。。。。。

 

所以要完成这样一个任务,传统的编程方式就是定义方法,其中建立循环,然后逐个遍历每一个元素,查看其是否符合条件,然后把符合条件的结果挑出来,放在一个返回值集合中,最后返回给调用者。这样的方法直接了当,清晰易懂。用了好多年了,但是写起来麻烦,简单点的都得个7,8行。于是.NET又进行了改进。

这是.NET2.0时代一种比较笨的方法:

 

代码1
复制代码
   
   
1 using System; 2   using System.Collections.Generic; 3   using System.Linq; 4   using System.Text; 5 6   namespace SelectTest1 7 { 8 class Product 9 { 10 public string Name { get ; private set ; } 11 public decimal Price { get ; private set ; } 12 13 public Product( string name, decimal price) 14 { 15 Name = name; 16 Price = price; 17 } 18 19 public Product() { } 20 21 public static List < Product > GetSampleProduct() 22 { 23 return new List < Product > 24 { 25 new Product{Name = " Watch " ,Price = 12345.56m }, 26 new Product{Name = " Knife " ,Price = 224.50m }, 27 new Product{Name = " Rope " ,Price = 12.50m }, 28 new Product{Name = " ETorch " ,Price = 5.5m } 29 }; 30 } 31 32 public override string ToString() 33 { 34 return string .Format( " {0} : {1} " , Name, Price); 35 } 36 } 37 38 class Program 39 { 40 static void Main( string [] args) 41 { 42 List < Product > ProductSample = Product.GetSampleProduct(); 43 foreach (Product tmp in ProductSample) 44 { 45 Console.WriteLine(tmp); 46 } 47 48 Console.WriteLine(); 49 50 Predicate < Product > test = delegate (Product p) { return p.Price > 10m; }; 51 List < Product > matches = ProductSample.FindAll(test); 52 53 Action < Product > print = delegate (Product p) { Console.WriteLine(p); }; 54 55 matches.ForEach(print); 56 } 57 } 58 } 59  
复制代码

 

关键代码是:

 

            Predicate<Product> test = delegate(Product p) { return p.Price > 10m; };
            List<Product> matches = ProductSample.FindAll(test);

 

            Action<Product> print = delegate(Product p) { Console.WriteLine(p); };

            matches.ForEach(print);

 

什么是Predicate,Action 呢?????这两个东西我很陌生。查MSDN!

 

Predicate<T> 是一个委托,它代表了一个方法,它的定义是:

namespace System
{
  // 摘要: 表示定义一组条件并确定指定对象是否符合这些条件的方法。  
  // 参数:
  // obj: 要按照由此委托表示的方法中定义的条件进行比较的对象。  
  // 类型参数:
  // T: 要比较的对象的类型。      
  //
返回结果:
  // 如果 obj 符合由此委托表示的方法中定义的条件,则为 true;否则为 false。  
  
public delegate bool Predicate < T > (T obj);
}

这个委托常被好多Array , List<T> 类的方法所使用,用来查找集合中的元素。

 

关于 Predicate,,跟 Action  的进一步使用,可以参考 Adil Akhter 的博文 :Using Predicate & Action of .Net2.0 。我看的时候简单翻译了一下:

 

“自从我开始做软件开发以来,我就得一次又一次得面对这样的情况:不得不遍历整个集合然后对每个元素做一些处理,或者根据某一个逻辑规则来筛选出一些元素。一次从一次地写那些循环语句真是太讨厌了。

.NET 2.0 解决了这个问题,我们只需要告诉集合如何筛选,如何处理每个元素,然后它自己会处理重复的步骤。让我们来看一下System.Collections.Generic命名空间中的List<T>类,看看它提供了哪些支持:

 

image

 

有大量的针对 查询,排序,筛选的支持方法。如果我们看一下我们经常说到的 FindAll 跟 ForEach :

public List<T> FindAll(Predicate<T> match);public void ForEach(Action<T> action);

会看到这儿的 Predicate 跟 Actor 是两个泛型委托,它们提供了一种方法,可以让我们灵活地对List中的每一个元素进行筛选或者执行某些处理。
让我们深入观察一下这两个委托:

Inside Predicate:

Predicate 是一个泛型委托,它利用了.NET 2.0提供的泛型特性。它的定义是:

delegate bool Predicate<T>(T obj)

如MSDN所定义, Predicate -

"represents a method that defines a set of criteria and determines whether the specific object meets this criteria."

 

简单地说,Predicate就是一个代表了接受一个T类型的参数,然后检查它是否满足某一规则然后返回 true 或者 false 的委托。示例如下:

在这个例子中,我们使用Predicate 来告诉集合如何筛选,然后集合会处理整个重复筛选的过程。

比如说,我们有一个 SprintBacklogItem 集合,想根据State==Closed 这一规则来进行筛选。我们就可以使用如下的一个方法:

   private bool HasStateClosed(SprintBacklogItem item) 
        { 
            if (item.State == SprintBackLogStatesStrings.CLOSED) 
                return true; 
            return false; 
        }

这个方法简单地检查了是否SprintBacklogItem's state is closed,然后返回true/false。现在如果我们观察一下这个方法的定义,就能够确认可以使用Predicate 委托来代表这个方法。下面这行代码就用 FindAll( ) 方法筛选出了所以关闭了的SprintBacklogItems

List<SprintBacklogItem> closedItems= _SprintBackLogsItems.FindAll(HasStateClosed);
Inside Action:

类似于 Predicate,

"Action is also one kind of generic delegate which represents a method that take the object as input and perform some operation on that."

定义:

delegate void Action<T>(T obj);

从这个委托的定义来看,它可以代表一种接受一个T类型的参数,然后什么也不返回的方法。

在List<T>中,由Action委托所代表的方法接受一个输入 obj 对象,然后对它进行处理。

Example

在这个例子中,我们将使用Action 对List中的每一个元素进行一个定义好的操作(initializing ActualHour = 10)

1. Define the method that will be represented by Action -

   public void InitActualHour(SprintBacklogItem item) 
        { 
            item.ActualHour = 10; 
        }

2. Following line of code initialize all the elements' Actual hour to 10 of the List -

this.ForEach(InitActualHour);

是不是很COOL很便捷呀? 为了不直接给Actor 以及 Predicate 定义方法,我们可以使用匿名方法处理委托。日后会讲到。今天先到这儿”

 

好了,Predicate 跟 Action 搞明白了,回到主题,接着看集合查询:

前面使用了这样的代码进行了筛选并输出结果,

 

            Predicate<Product> test = delegate(Product p) { return p.Price > 10m; };
            List<Product> matches = ProductSample.FindAll(test);

 

            Action<Product> print = delegate(Product p) { Console.WriteLine(p); };

            matches.ForEach(print);

 

其实这两句可以合并成一句:

 

ProductSample.FindAll(delegate (Product p){return p.Price>10m;}).ForEach(delegate (Product p){Console.WriteLine(p);});

 

是不是很简洁呀,呵呵。当然从来都是没有最XX,只有更XX,看下面的,LAMBDA出场!!!!!:

 

ProductSample.FindAll(p=> p.Price > 10m).ForEach(p=>Console.WriteLine(p));

 

爽吧。

 

爽的方法还不止一种,还可以这样爽:

 

            foreach(Product tmp in ProductSample.Where(p=>p.Price > 10m))
            {
                Console.WriteLine(tmp);
            }

 

注意这个针对List<T>的 Where() 方法,呀呀呀,,,还有上一节的 OrderBy() 真是把能一般情况都考虑到了。

 

但是,有些人觉得那么写还不够爽,在C# 3.0中就弄出了个LINQ。。。。。这个内容就多了。。。日后再说。。。

   
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值