续上面

来源:互联网 发布:c语言char字符串 编辑:程序博客网 时间:2024/05/01 20:08
///<summary>/// 定义一个静态类,用于实现扩展方法///</summary>publicstaticclass MyExtensionMethods {///<summary>/// 商品查询器///</summary>///<param name="productEnum">扩展类型的实例引用</param>///<param name="selectorParam">一个参数类型为Product,返回值为bool的委托</param>///<returns>查询结果</returns>public static IEnumerable<Product> Filter(this IEnumerable<Product> productEnum, Func<Product bool> selectorParam) {foreach (Product prod in productEnum) {if (selectorParam(prod)) {yieldreturn prod;            }        }    }}

没错,我们就是用这么简短的Filter方法来满足各种需求的查询。上面Product类使用的是前文定义的。这里也再一次见证了扩展方法的功效。为了演示Filter查询方法的调用,我们先来造一批数据:

staticvoid Main(string[] args) {// 创建商品集合    IEnumerable<Product> products = new ShoppingCart {        Products = new List<Product> { new Product {Name = "西瓜", Category = "水果", Price = 2.3M}, new Product {Name = "苹果", Category = "水果", Price = 4.9M}, new Product {Name = "ASP.NET MCV 入门", Category = "书籍", Price = 19.5M}, new Product {Name = "ASP.NET MCV 提高", Category = "书籍", Price = 34.9M}         }    };}

接下来我们继续在上面Main方法中来调用查询方法Filter:
//用匿名函数定义一个具体的查询需求

Func<Product, bool> fruitFilter = delegate(Product prod) {return prod.Category == "水果";};

//调用Filter,查询分类为“水果”的商品

IEnumerable<Product> filteredProducts = products.Filter(fruitFilter);//打印结果foreach (Product prod in filteredProducts) {    Console.WriteLine("商品名称: {0}, 单价: {1:c}", prod.Name, prod.Price);} Console.ReadKey();

上面我们使用的是委托和匿名函数来处理用户查询逻辑,并把它传递给Filter方法,满足了前面所说的需求。但若使用Lambda表达式代替上面的匿名函数能使上面的代码看上去更简洁更人性化,如下代码所示:

Func<Product, bool> fruitFilter = prod => prod.Category == "水果";IEnumerable<Product> filteredProducts = products.Filter(fruitFilter);

没有了delegate关键字,没有了大小括号,看上去更舒服。当然上面两行代码可以继续简化为一行:

IEnumerable<Product> filteredProducts = products.Filter(prod => prod.Category == "水果");

这三种方式输出结果都是一样的。然后,我们还可以通过Lambda表达式实现各种需求的查询:
//查询分类为“水果”或者单价大于30元的商品

IEnumerable<Product> filteredProducts = products.Filter(prod =>    prod.Category == "水果" || prod.Price >30);

6.LINQ
最后简单回顾一下LINQ。LINQ(Language Integrated Query语言集成查询)是 VS 2008 和 .NET Framework 3.5 版中一项突破性的创新,它在对象领域和数据领域之间架起了一座桥梁。
上面讲Lambda表达式时,用到的查询结果集的方式未免还是有点麻烦(因为自定义了一个Filter扩展方法),而Linq本身就集合了很多扩展方法,我们可以直接使用,大大的简化了编写查询代码的工作。例如,对于这样一个数据集合:

Product[] products = {new Product {Name = "西瓜", Category = "水果", Price = 2.3M}, new Product {Name = "苹果", Category = "水果", Price = 4.9M}, new Product {Name = "空心菜", Category = "蔬菜", Price = 2.2M}, new Product {Name = "地瓜", Category = "蔬菜", Price = 1.9M} };

如果要查询得到价钱最高的三个商品信息,如果不使用Linq,我们可能会先写一个排序方法,对products根据价钱由高到低进行排序,排序时需要创建一个新的Product[]对象用于存储排序好的数据。但用Linq可大大减少工作量,一两句代码就能搞定。如下代码所示,查出价钱最高的三个商品:

var results = from product in productsorderby product.Price descendingselectnew {                    product.Name,                    product.Price                };//打印价钱最高的三个商品int count = 0;foreach (var p in results) {    Console.WriteLine("商品:{0},价钱:{1}", p.Name, p.Price);if (++count == 3) break;}Console.ReadKey();

能熟练使用Linq是一件很爽的事情。上面的Linq语句和我们熟悉的SQL查询语句类似,看上去非常整洁且易懂。但并不是每一种SQL查询语句在C#都有对应的关键字,有时候我们需要使用另外一种Linq查询方式,即“点号”方式的Linq查询方式,这种方式中的Linq查询方法都是扩展方法。如下面这段代码和上面实现的效果是一样的:

var results = products    .OrderByDescending(e => e.Price)    .Take(3)    .Select(e =>new { e.Name,e.Price});foreach (var p in results) {    Console.WriteLine("商品:{0},价钱:{1}", p.Name, p.Price);}Console.ReadKey();

虽然类SQL的Linq查询方式比这种方式看上去更一目了然,但并不是每一种SQL查询语句在C#都有对应的关键字,比如这里的Take扩展方法就是类SQL的Linq查询语法没有的功能。
注意,有些Linq扩展方法分为“延后查询”(deferred)和“即时查询”(immediate)。延后查询意思是拥有“延后查询”扩展方法的Linq语句只有当调用结果集对象的时候才开始真正执行查询,即时查询则是立即得到结果。比如上面的Linq语句的OrderByDescending扩展方法就是一个“延后查询”方法,当程序执行到Linq语句定义部分时并没有查询出结果并放到results对象中,而是当程序执行到foreach循环时才真正执行Linq查询语句得到查询结果。我们可以做个测试,在Ling语句之后,我们再将products[1]对象重新赋值,如下代码所示:

var results = products    .OrderByDescending(e => e.Price)    .Take(3)    .Select(e =>new { e.Name, e.Price });//在Linq语句之后对products[1]重新赋值products[1] = new Product { Name = "榴莲", Category = "水果", Price = 22.6M };//打印foreach (var p in results) {    Console.WriteLine("商品:{0},价钱:{1}", p.Name, p.Price);}Console.ReadKey();
原创粉丝点击