C# LINQ需求實現演化

libingql發表於2014-05-31

  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
            });

 

相關文章