C# LINQ需求实现演化
Linq是C#3.0引入的,在C#2.0实现从集合中过滤符合条件的记录实现方式。
假设有一个Book类,以及一个Book类的集合,现在需要从集合中查找出单价大于50的Book。
1、固定查询字段的实现方式:
Book.cs类:
using System; using System.Collections.Generic; using System.Text; namespace LINQTest { public class Book { public string Title { get; set; } public decimal Price { get; set; } public string Author { get; set; } public string ISBN { get; set; } } }
Help.cs类:
using System; using System.Collections.Generic; using System.Text; namespace LINQTest { public class Helper { public static IList<Book> SearchBookByPrice() { IList<Book> books = new List<Book> { new Book{Title="Book1", Author="Author1", ISBN="ISBN1", Price=30}, new Book{Title="Book2", Author="Author2", ISBN="ISBN2", Price=40}, new Book{Title="Book3", Author="Author3", ISBN="ISBN3", Price=50}, new Book{Title="Book4", Author="Author4", ISBN="ISBN4", Price=60} }; IList<Book> results = new List<Book>(); foreach (Book book in books) { if (book.Price >= 50) { results.Add(book); } } return results; } } }
Program.cs类:
using System; using System.Collections.Generic; using System.Text; namespace LINQTest { class Program { static void Main(string[] args) { foreach (Book book in Helper.SearchBookByPrice()) { Console.WriteLine("{0}-{1}", book.Title, book.Price); } } } }
上面的代码中实现了根据Price查询集合中大于50的记录。但是当需求有变动,需要根据Title来查询时,则上面的实现方法需要另外进行编写按Title查询的方法。
2、不固定查询字段的实现方式
查询条件最后返回的只是true或false,在新定义的方法中,只要if语句中返回为true的记录,添加到集合中即可,而不需要去知道具体是什么查询条件。
Helper.cs类:
using System; using System.Collections.Generic; using System.Text; namespace LINQTest { public class Helper { public delegate bool Condition(Book book); public bool ConditionTitle(Book book) { return book.Title == "Book2"; } public bool ConditionPrice(Book book) { return book.Price >= 50; } public static IList<Book> SearchBookByCondition(Condition condition) { IList<Book> books = new List<Book> { new Book { Title = "Book1", Author = "Author1", ISBN = "ISBN1", Price = 30 }, new Book { Title = "Book2", Author = "Author2", ISBN = "ISBN2", Price = 40 }, new Book { Title = "Book3", Author = "Author3", ISBN = "ISBN3", Price = 50 }, new Book { Title = "Book4", Author = "Author4", ISBN = "ISBN4", Price = 60 } }; IList<Book> results = new List<Book>(); foreach (Book book in books) { if (condition(book)) { results.Add(book); } } return results; } } }
Program.cs类:
using System; using System.Collections.Generic; using System.Text; namespace LINQTest { class Program { static void Main(string[] args) { //Helper.Condition condition = new Helper.Condition(new Helper().ConditionTitle); Helper.Condition condition = new Helper().ConditionTitle; foreach (Book book in Helper.SearchBookByCondition(condition)) { Console.WriteLine("{0}-{1}", book.Title, book.Price); } } } }
以上的实现方式采用委托delegate,在C#2.0中还提供了匿名方法,集合中过滤查询条件的代码可修改为:
Helper.Condition condition = delegate(Book book) { return book.Title == "Book2"; };
IList<Book> results = Helper.SearchBookByCondition(delegate(Book book) { return book.Title == "Book2"; });
在C#3.0提供了Lambda表达式,则实现集合过滤方式为:
IList<Book> results = Helper.SearchBookByCondition(book => book.Title == "Book2");
但这样实现每次都要带类名Helper,我们希望IList自身就具有这个方法,C#3.0提供了扩展方法。
3、C#3.0扩展方法实现方式
public static class Helper { public delegate bool Condtion(Book book); public static IList<Book> Where(this IList<Book> books, Condtion condition) { IList < Book > results = new List<Book>(); foreach (Book book in books) { if (condition(book)) { results.Add(book); } } return results; } }
IList<Book> results = books.Where(book => book.Title == "Book2");
5、IEnumberable实现方式
由于IList都继承自IEnumberable,则可以通过扩展IEnumberable来实现。
public static class Helper { public delegate bool Condtion<T>(T t); public static IEnumerable<T> Where<T>(this IEnumerable<T> items, Condtion<T> condition) { foreach (T t in items) { if (condition(t)) { yield return t; } } } }
6、通用扩展类
using System; using System.Collections.Generic; using System.Text; namespace LINQTest { public class Extension { public delegate TResult Func<T, TResult>(T t); public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> filter) { foreach (T item in source) { if (filter(item)) { yield return item; } } } public static IEnumerable<TResult> Select<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector) { foreach (T item in source) { yield return selector(item); } } } }
var result = books.Where(book => book.Title == "Book2").Select(book => new { Key = book.Title,Value=book.Price });