07-01 C# Linq的诞生

一、linq存在的意义

linq的存在是为了对数据进行操作,诞生于dotnet framework 3.0。

二、linq诞生过程

思考

现在有一个Person集合,我们需要根据不同的条件筛选出对应的人员,又哪些方案?

1、方案一:通过循环和if判断来筛选数据

缺点:

  • 代码量大,不够简洁,特别是遇到复杂条件之后,会很麻烦
  • 随着条件的变更,每次都要重新定义循环,有冗余代码
/// <summary>
/// 从一个数据集中过滤数据的一般方法
/// </summary>
public void GeneralMethod()
{
    //获取全部的人员数据
    var person = new Person();
    var personList = person.GetPersopnList();

    {
        Console.WriteLine("==================常规情况下过滤数据================");
        {
            //1、要求查询id小于3的人员
            var resultList = new List<Person>();
            //可以使用for循环遍历,将满足条件的随想添加到resultList集合中
            foreach (var item in personList)
            {
                if (item.Id < 3)
                {
                    resultList.Add(item);
                }
            }
            //循环完成之后,resultList中就是满足条件的对象
        }

        {
            //2、获取名字为三个字的人员
            var resultList = new List<Person>();
            foreach (var item in personList)
            {
                if (item.Name.Length == 3)
                {
                    resultList.Add(item);
                }
            }
            //循环完成后,resultList中就是满足条件的对象
        }

        {
            //3、获取名字小于三个数,id大于2,年龄大于15的人员(复杂条件)
            var resultList = new List<Person>();
            foreach (var item in personList)
            {
                if (item.Id > 2
                    && item.Name.Length < 3
                    && item.Age > 15)
                {
                    resultList.Add(item);
                }
            }
            //循环完成后,resultList中就是满足条件的对象
        }
        //由上面三种可以看出,通过循环是可以得到想要的数据,但是不够简洁,特别是遇到复杂条件之后,会很麻烦
    }
}

思考:那么针对上面两个问题,解决方案是:封装,增加一个扩展方法,见方案二。

2、方案二:扩展方法
(1)最初版本

优点

  • 调用方代码量就很少了

缺点

  • 该方法只能满足一种条件的过滤
/// <summary>
/// 封装一下之后,调用方的代码量就很少了,但是缺点也很明显
///     
///     该方法只能满足一种条件的过滤,那如果想更换条件怎么办呢?
/// </summary>
/// <param name="persons"></param>
/// <returns></returns>
public static List<Person> MyWhere(this List<Person> persons)
{
    var resultList = new List<Person>();
    //可以使用for循环遍历,将满足条件的随想添加到resultList集合中
    foreach (var item in persons)
    {
        if (item.Id < 3)
        {
            resultList.Add(item);
        }
    }
    return resultList;
}

思考:那如果想更换条件怎么办呢?—>继续进化

(2)进化版本

分析

  1. 筛选数据,不管条件则么变化,for循环是必须的,唯一的区别就是过滤条件不同(逻辑不同)
  2. 逻辑即动作,动作即方法,因此逻辑及方法,因为委托可以把方法当作参数传递
  3. 那么就很好办了,我们就可以使用委托来解决这个问题

那么这个委托怎么定义呢?

  1. 观察过滤条件,如 if (item.Id < 3),无论是根据名称还是id过滤,都必须需要当前过滤的对象
  2. 判断条件的返回值是个bool类型
    因此: 只需要传递一个参数为Person,返回值为bool的委托

优点:

  • 逻辑解耦,更加灵活

缺点:

  • 不够灵活,只能给某个特定的对象使用,不能通用
/// <summary>
/// 如何解决上面方法带来的问题呢?
/// 
/// 分析:
/// 
/// 1、筛选数据,不管条件则么变化,for循环是必须的,唯一的区别就是过滤条件不同(逻辑不同)
/// 2、逻辑即动作,动作即方法,因此逻辑及方法,因为委托可以把方法当作参数传递
/// 3、那么就很好办了,我们就可以使用委托来解决这个问题
/// 
/// 那么这个委托怎么定义呢?
/// 1、观察过滤条件,如 if (item.Id < 3),无论是根据名称还是id过滤,都必须需要当前过滤的对象
/// 2、判断条件的返回值是个bool类型
/// 因此: 只需要传递一个参数为Person,返回值为bool的委托
///  /// </summary>
/// <param name="persons"></param>
/// <returns></returns>
public static List<Person> MyWhere(this List<Person> persons, Func<Person, bool> func)
{
    var resultList = new List<Person>();
    //可以使用for循环遍历,将满足条件的随想添加到resultList集合中
    foreach (var item in persons)
    {
        if (func.Invoke(item))
        {
            resultList.Add(item);
        }
    }
    return resultList;
}

思考:如何做到通用呢?答案是:泛型方法

(3)最终版本

优点:

  • 逻辑解耦
  • 通用
/// <summary>
/// 
/// 最终形态:
/// 
///     这就是linq 的where扩展方法的本质
///     	把固定不变的逻辑封装起来,把可变的逻辑封装成委托来传递的扩展方法
/// </summary>
/// <param name="resource"></param>
/// <param name="func"></param>
/// <returns></returns>
public static List<T> MyWhere<T>(this List<T> resource, Func<T, bool> func) where T : class
{
    var resultList = new List<T>();
    //可以使用for循环遍历,将满足条件的随想添加到resultList集合中
    foreach (var item in resource)
    {
        if (func.Invoke(item))
        {
            resultList.Add(item);
        }
    }
    return resultList;
}

调用:

/// <summary>
/// 执行扩展方法
/// </summary>
public void ExecExtensionMethod()
{
    var person = new Person();
    var personList = person.GetPersopnList();
    var resultList = new List<Person>();
    Console.WriteLine("===============通过自定义扩展方法完成上述的情况=================");
    {
        //1、查询id小于3的人员

        //实例化一个委托
        Func<Person, bool> func = s => s.Id < 3;
        //调用扩展方法
        resultList = personList.MyWhere(func);
        //进一步简化
        resultList = personList.MyWhere(s => s.Id < 3);
        person.PrintList(resultList);
    }

    {
        //2、获取名字小于三个数,id大于2,年龄大于15的人员
        resultList = personList.MyWhere(p => p.Name.Length < 3 && p.Id > 2 && p.Age > 15);
        person.PrintList(resultList);
    }
}
#endregion

输出结果:
在这里插入图片描述

观察

仔细观察下面两幅截图,能得到什么结论?

(1)自定义MyWhere扩展方法在这里插入图片描述
(2)linq的where扩展方法
在这里插入图片描述
不难得出结论:其实二者本质是一样的,没有任何的区别-------没错,其实linq的where扩展方法就是这么实现的,linq的扩展方法就是这样(通过泛型方法和委托将固定不变的逻辑封装起来,将可变的逻辑封装成委托传递)实现的。

三、本文代码

LinqShow.cs
MethodExtension.cs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值