一、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)进化版本
分析:
- 筛选数据,不管条件则么变化,for循环是必须的,唯一的区别就是过滤条件不同(逻辑不同)
- 逻辑即动作,动作即方法,因此逻辑及方法,因为委托可以把方法当作参数传递
- 那么就很好办了,我们就可以使用委托来解决这个问题
那么这个委托怎么定义呢?
- 观察过滤条件,如 if (item.Id < 3),无论是根据名称还是id过滤,都必须需要当前过滤的对象
- 判断条件的返回值是个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的扩展方法就是这样(通过泛型方法和委托将固定不变的逻辑封装起来,将可变的逻辑封装成委托传递)实现的。