手寫Linq To Object

1、數據準備

public class Student
{
    public string Name { get; set; }

    public int Age { get; set; }
}

var studentList = new List<Student>();
Student student1 = new Student();
student1.Name = "張三";
student1.Age = 30;

Student student2 = new Student();
student2.Name = "李四";
student2.Age = 29;

Student student3 = new Student();
student3.Name = "趙春來";
student3.Age = 28;

studentList.Add(student1);
studentList.Add(student2);
studentList.Add(student3);

 

2、看看Where是什麼?
studentList.Where是接受泛型繼承IEnumerable類型的數據源,和接受泛型類型返回布爾值的委託,返回IEnumerable類型的擴展方法

 

3、原始寫法

a、foreash 遍歷集合得寫兩遍
b、添加到結果集合得寫兩遍
不同的是查詢條件不同

//查找年齡小於30的學生
{
    var list = new List<Student>();
    foreach (var item in studentList)
    {
        if (item.Age < 30)
        {
            list.Add(item);
        }
    }
}
//查找姓名大於2個字的學生
{
    var list = new List<Student>();
    foreach (var item in studentList)
    {
        if (item.Name.Length > 2)
        {
            list.Add(item);
        }
    }
}

4、第一次封裝Linq To Object

a、把集合傳遞進去
b、把查詢條件傳遞進去--返回布爾值的委託

//1、調用第一次封裝Linq to Object
CustomerWhereOne(studentList, ((s) => s.Age < 30));
CustomerWhereOne(studentList, new Func<Student, bool>(s => s.Name.Length > 2));

/// <summary>
/// 1、第一次封裝Linq To Object
/// </summary>
/// <param name="resource">數據源</param>
/// <param name="func">返回布爾值的委託</param>
public static List<Student> CustomerWhereOne(List<Student> resource, Func<Student, bool> func)
{
    var result = new List<Student>();
    foreach (var item in resource)
    {
        if (func(item))
        {
            result.Add(item);
        }
    }

    return result;
}

5、第二次封裝Linq To Object
a、改爲泛型--List<T>
b、改爲擴展方法

//2、調用第二次封裝Linq To Object
{
    var resultList = studentList.CustomerWhereTwo((s) => s.Age < 30);
    var resultList2 = studentList.CustomerWhereTwo(new Func<Student, bool>(s => s.Name.Length > 2));

    foreach (var item in resultList)
    {
        Console.WriteLine(item.Name);
    }
}

/// <summary>
/// 2、第二次封裝Linq To Object,改爲泛型,改爲擴展方法
/// </summary>
/// <param name="resource">數據源</param>
/// <param name="func">返回布爾值的委託</param>
public static List<T> CustomerWhereTwo<T>(this List<T> resource, Func<T, bool> func)
{
    var result = new List<T>();
    foreach (var item in resource)
    {
        if (func(item))
        {
            result.Add(item);
        }
    }

    return result;
}

6、第三次封裝Linq To Object,改爲yield迭代器模式,完成了數據的按需獲取,延遲加載
yield和IEnumerable配合使用
a、返回值類型改爲IEnumerable
b、return前面加yield

//3、調用第三次封裝Linq to Object
{
    var resultList = studentList.CustomerWhereThree((s) => s.Age < 30);
    var resultList2 = studentList.CustomerWhereThree(new Func<Student, bool>(s => s.Name.Length > 2));
    foreach (var item in resultList)
    {
        Console.WriteLine(item.Name);
    }
}

/// <summary>
/// 3、第三次封裝Linq To Object,改爲迭代器模式,完成了數據的按需獲取,延遲加載
/// </summary>
/// <param name="resource">數據源</param>
/// <param name="func">返回布爾值的委託</param>
public static IEnumerable<T> CustomerWhereThree<T>(this IEnumerable<T> resource, Func<T, bool> func)
{
    var result = new List<T>();
    foreach (var item in resource)
    {
        if (func(item))
        {
            yield return item;
        }
    }
}

調試代碼,我們發現resultList返回的是個ResultView,且提示當展開結果視圖枚舉IEnumerable

只有當真正使用,去遍歷的時候纔去調用真正去調用CustomerWhereThree

至此我們通過一步步封裝了一個和內置Where一樣的CustomerWhereThree方法--Linq To Object

  • 總結

1、Linq是基於委託的封裝(例子中的--func),邏輯解耦(查詢條件可變化的部分傳遞進去 --s.Age < 30和s.Name.Length > 2),代碼重用(把循環遍歷集合和添加到結果集這樣的動作封裝了起來--foreach (var item in resource))。
2、IEnumerable--yield--利用的迭代器的延遲,按需獲取。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章