C#基础--Lambda和LINQ

这篇具有很好参考价值的文章主要介绍了C#基础--Lambda和LINQ。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C#基础–Lambda 和 LINQ

一、Lambda 的前世今生

在.NetFramewok的不同版本都有不同的样子;在.NetCore下也都是支持的;

1.1 .Netframework1.0/1.1时代

public delegate void NoReturnWithPara(int x, string y);

NoReturnWithPara method = new NoReturnWithPara(Study);
method.Invoke(123, "Richard");

private void Study(int id, string name)
{
    Console.WriteLine($"{id} {name} 学习.Net高级班");
}

1.2 .NetFramework2.0

匿名方法 增加了一个delegate关键字, 可以访问到除了参数以外的局部变量

public delegate void NoReturnWithPara(int x, string y);

int i =0;
NoReturnWithPara method = new NoReturnWithPara(delegate (int id, string name)
{
	Console.WriteLine($"{id} {name} 学习.Net高级班");
	Console.WriteLine(i);	//可以访问到除了参数以外的局部变量 i
});
method.Invoke(123, "Richard");

1.3 .NetFramework3.0 前期

去掉了delegate关键字,添加了一个=> goes to

public delegate void NoReturnWithPara(int x, string y);

int i =0;
NoReturnWithPara method = new NoReturnWithPara((int id, string name) =>
{
	Console.WriteLine($"{id} {name} 学习.Net高级班");
	Console.WriteLine(i);
});
method.Invoke(123, "Richard");

1.4 .NetFramework3.0 后期

去掉了匿名方法后的参数类型,编译器自动推断来的/编译器提供的便捷功能(语法糖)

public delegate void NoReturnWithPara(int x, string y);

int i =0;
NoReturnWithPara method = new NoReturnWithPara((id, name) =>  //编译器自动推断来的/编译器提供的便捷功能(语法糖)
{
	Console.WriteLine($"{id} {name} 学习.Net高级班");
	Console.WriteLine(i);
});
method.Invoke(123, "Richard");

如果匿名方法体中只有一行代码,可以省略方法体的大括号:

public delegate void NoReturnWithPara(int x, string y);

NoReturnWithPara method = new NoReturnWithPara((id, name) => Console.WriteLine($"{id} {name} 学习.Net高级班"));
method.Invoke(123, "Richard");
public delegate void NoReturnWithPara(int x, string y);

NoReturnWithPara method = (id, name) => Console.WriteLine($"{id} {name} 学习.Net高级班");
method.Invoke(123, "Richard");

如果只有一个参数的时候:

Action<string> method = sn => Console.WriteLine($"欢迎{sn} 来到.Net高级班进阶学习");
method.Invoke("牧羊人");

如果有返回值? 如果lambda表达式中只有一行代码,且有返回值,可以省略return;

Func<string> func0 = () => { return "黄大仙" };

//如果有返回值? 如果lambda表达式中只有一行代码,且有返回值,可以省略 `大括号` + `return`;
Func<string> func = () => "黄大仙";
Func<int, string> func1 = i => i.ToString();

大家觉得Lambda表达式本质是什么?

多播委托中可以把Lambda表达式+=,但是不能把Lambda表达式-=。因为Lambda表达式其实是一个方法,不同的lambda表达式就是不同的方法。

Lambda的本质是一个方法。

语法糖:编译器提供的便捷功能

二、LINQ

初始化数据

List<Student> studentList = new List<Student>()
{
    new Student() { Id=1, Name="赵亮", ClassId=2, Age=35 },
    new Student() { Id=2, Name="再努力一点", ClassId=2, Age=23 },
    new Student() { Id=3, Name="王炸", ClassId=2, Age=27 },
    new Student() { Id=4, Name="疯子科学家", ClassId=2, Age=26 },
    new Student() { Id=5, Name="灭", ClassId=2, Age=25 },
    new Student() { Id=6, Name="黑骑士", ClassId=2, Age=24 },
    new Student() { Id=7, Name="故乡的风", ClassId=2, Age=21 },
    new Student() { Id=8, Name="晴天", ClassId=2, Age=22 }
};

2.1 Linq 扩展方法&表达式

var list = studentList.Where<Student>(s => s.Age < 30); //list里面必然是符合要求的数据;
var list = from s in studentList
			where s.Age < 30
			select s;   //list里面必然是符合要求的数据;

以上两种都是LINQ。

2.2 linq to object

Linq – Linq to object:就是针对IEnumerable类型数据

​ 1. IEnumerable 类型数据:可以理解为内存中的数据;其实就是把不变的逻辑封装起来,把可变的逻辑封装成委托来传递;

​ 2. IQueryable 类型数据:可以理解成内存数据—来自于数据库的数据;

延伸:

Linq to Sql:就是把打开数据库连接,查询数据(不变的的逻辑),把sql 的拼装(可变的逻辑)

Linq to Xml:把数据解析这类动作封装起来(不变的逻辑), 把数据筛选条件封装成委托来传递(可变的逻辑)

Linq to Redis:把固定的逻辑封装起来,把不变的逻辑封装成委托传递

Linq to Cache:…

Linq to JSON:…

Linq to Everything:…

IQueryable 和 IEnumerable 存在本质的区别:

  1. 使用IQueryable 查询
List<Student> studentList = this.GetStudentList();

var query = studentList.AsQueryable();
query.Where(a => a.Age < 30);

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
  1. 使用 IEnumerable 查询
List<Student> studentList = this.GetStudentList();

var query = studentList.AsEnumerable();
query.Where(a => a.Age < 30);

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

IEnumerable 传递的是一个委托,而 IQueryable 传递的是一个表达式目录树(数据结构)

现在大家觉得Linq 是什么?

Linq 是一种封装思想,对于用户来说,就把不需要关心内部怎么实现,只需要Linq一下即可;微软之前很推崇这种思想,只让开发者关注自己的核心逻辑,不需要关注内部逻辑,彻底的把开发者变成编程小白;如果大家有经验的话,你会发现像Asp .Net MVC就属于傻瓜式开发,成套的;我们不用去关心原理就可以直接上手。

但是现在又变了,现在有更高的要求,像是Linq to JSON、Linq to Redis等并没有人来封装这些。如果大家有兴趣,可以去尝试封装一下。

2.3 基本查询

var list = studentList.Where<Student>(s => s.Age < 30)
                                     .Select(s => new
                                     {
                                         IdName = s.Id + s.Name,
                                         ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                                     });
var list = from s in studentList
            where s.Age < 30
            select new
			{
                IdName = s.Id + s.Name,
                ClassName = s.ClassId == 2 ? "高级班" : "其他班"
            };

Select 方法:

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);

**备注:**使用 studentList.Where(s => s.Age < 30) 查询并返回数据后,实际内容还是一个 IEnumerable 的数据。但是接着再使用了Select 做投影的话,里面创建了一个匿名对象,返回的也是一个匿名对象。

2.4 分页

var list = studentList.Where<Student>(s => s.Age < 30)//条件过滤
                                     .Select(s => new//投影
                                     {
                                         Id = s.Id,
                                         ClassId = s.ClassId,
                                         IdName = s.Id + s.Name,
                                         ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                                     })
                                     .OrderBy(s => s.Id)//排序
                                     .ThenBy(s=>s.ClassName)    //多重排序,可以多个字段排序都生效
                                     .OrderByDescending(s => s.ClassId)//倒排
                                     .Skip(2)//跳过几条
                                     .Take(3)//获取几条
                                     ;

性能怎样?=> 本质其实都是循环;

2.5 分组

var list = from s in studentList
            where s.Age < 30
            group s by s.ClassId into sg
            select new
            {
                key = sg.Key,
                maxAge = sg.Max(t => t.Age)
            };
var list = studentList.Where(a=>a.Age<30)
    					.GroupBy(c => c.ClassId)
    					.Select(sg => new
                		{
                            key = sg.Key,
                            maxAge = sg.Max(t => t.Age)
                        });

2.6 内连接 – inner join

var list = from s in studentList
            join c in classList on s.ClassId equals c.Id
            select new
            {
                Name = s.Name,
                CalssName = c.ClassName
            };
var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
                {
                    Name = s.Name,
                    CalssName = c.ClassName
                });

2.7 左连接 – left join

var list = from s in studentList
   		join c in classList on s.ClassId equals c.Id
   		into scList
           from sc in scList.DefaultIfEmpty()
           select new
           {
               Name = s.Name,
               CalssName = sc == null ? "无班级" : sc.ClassName//c变sc,为空则用
           };
var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
                {
                    Name = s.Name,
                    CalssName = c.ClassName
                }).DefaultIfEmpty();

三、自定义封装

3.1 针对一个具体类的封装

/// <summary>
/// 如果换个条件怎么办?
/// 使用委托:委托可以把方法当做参数传递;方法其实是逻辑,委托可以把逻辑当做参数传递;
/// 委托:应该是返回值为bool的委托,参数是一个Student
/// </summary>
/// <param name="resource"></param>
/// <returns></returns>
public static List<Student> RichardWhere(this List<Student> resource, Func<Student, bool> func)
{
    List<Student> list = new List<Student>();
    foreach (var item in resource)
    {
        //if (item.Name.Length > 2) //条件的判断其实就是逻辑---动作 //唯一的区别就在与中间这里的条件不一样;
        if (func.Invoke(item))
        {
            list.Add(item);
        }
    }
    return list;
}

3.2 通用–泛型封装

/// <summary>
/// 这就是Linq中where的本质;
/// 1. 是把固定不变的逻辑,封装起来,把可变的逻辑封装成委托来传递
/// 就可以让开发者只需要关注自己的核心业务,其他别的都以LINQ封装
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="resource"></param>
/// <param name="func"></param>
/// <returns></returns>
public static List<T> RichardWhere<T>(this List<T> resource, Func<T, bool> func) where T:class
{
    List<T> list = new List<T>();
    foreach (var item in resource)
    {
        //if (item.Name.Length > 2) //条件的判断其实就是逻辑---动作 //唯一的区别就在与中间这里的条件不一样;
        if (func.Invoke(item))
        {
            list.Add(item);
        }
    }
    return list;
}
/// <summary>
/// 有什么好处?
/// 通过接口来扩展,只要实现了这个接口的,都可以使用当前这个扩展方法
/// 相比而言:自然扩展抽象要好一些,扩展性更好
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="resource"></param>
/// <param name="func"></param>
/// <returns></returns>

public static IEnumerable<T> RichardWhereEnumerable<T>(this IEnumerable<T> resource, Func<T, bool> func) where T : class
{
    List<T> list = new List<T>();
    foreach (var item in resource)
    {
        //if (item.Name.Length > 2) //条件的判断其实就是逻辑---动作 //唯一的区别就在与中间这里的条件不一样;
        if (func.Invoke(item))
        {
            list.Add(item);
        }
    }
    return list;
}

3.3 实际运用

如果是学生类的实现对象的话,3.1 和3.2都是的话下面代码一样,无需任何修改

var list1 = MethodExtension.RichardWhere(studentList, item => item.Age < 30);
var list2 = studentList.RichardWhere(item => item.Age < 30);

var list1 = MethodExtension.RichardWhere(studentList, item => item.Name.Length > 2);
var list2 = studentList.RichardWhere(item => item.Name.Length > 2);

var list1 = MethodExtension.RichardWhere(studentList, item => item.Id > 1
                                         && item.Name != null
                                         && item.ClassId == 1
                                         && item.Age > 20);
//循环完毕以后,list里面必然是符合要求的数据;
var list2 = studentList.RichardWhere<Student>(item => item.Id > 1
                                              && item.Name != null
                                              && item.ClassId == 1
                                              && item.Age > 20);

四、yield 使用

/// <summary>
/// yield` 必须和 IEnumerable<T> 配合使用,可以做到按需获取
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="resource"></param>
/// <param name="func"></param>
/// <returns></returns>
public static IEnumerable<T> RichardWhereIterator<T>(this IEnumerable<T> resource, Func<T, bool> func) where T : class
{
    foreach (var item in resource)
    {
        if (func.Invoke(item))
        {
            yield return item;
        }
    }
    return list;
}

var list3 = studentList.RichardWhereIterator(item => item.Age < 30);
foreach (var item in list3)
{
    Console.WriteLine("Name={0}  Age={1}", item.Name, item.Age);
}

yield 必须和 IEnumerable<T> 配合使用,可以做到按需获取;如果返回值换成 List<T> 就会产生报错

按需获取: var list3 = studentList.RichardWhereIterator(item => item.Age < 30); 执行完之后,并没有实质性执行到 RichardWhereIterator 方法内部,直到 foreach (var item in list3) 的时候,才执行到方法体内,而且是循环一次就到 RichardWhereIterator 获取一条数据。

C#基础--Lambda和LINQ,C# .Net,c#,linq

使用yield 的使用,编译器会生成一个泛型的,会有个迭代状态机 [IteratorStateMachine] (属于特性)文章来源地址https://www.toymoban.com/news/detail-581834.html

到了这里,关于C#基础--Lambda和LINQ的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#基础:利用LINQ进行复杂排序

    请你写出linq对表格排序, CODE=3排前面 ,其余按照 CODE降序 排序,CODE一样再按照 字母升序 排序 ID CODE VALUE A0001 1 A A0002 1 B A0003 1 C A0004 2 D A0005 2 E A0006 2 F A0007 3 G A0008 3 H A0009 3 I A0010 4 J 若再加大难度,ID=A0005的排第一,然后CODE=3排前面,其余按照CODE降序排序,再按照字母升序排

    2024年01月18日
    浏览(24)
  • 【C# 基础精讲】LINQ to Objects查询

    LINQ to Objects是LINQ技术在C#中的一种应用,它专门用于对内存中的对象集合进行查询和操作。通过使用LINQ to Objects,您可以使用统一的语法来查询、过滤、排序、分组等操作各种.NET对象。本文将详细介绍LINQ to Objects的基本概念、常见的操作和示例,以帮助您更好地理解如何在

    2024年02月11日
    浏览(23)
  • 【C# 基础精讲】LINQ to XML查询

    LINQ to XML 是 C# 中用于查询和操作 XML 数据的强大工具。它允许您使用 LINQ 查询语法对 XML 文档进行查询、过滤、投影等操作,从而更加方便地处理 XML 数据。本文将详细介绍 LINQ to XML 的基本概念、常见操作以及示例,帮助您了解如何在 C# 中使用 LINQ to XML 进行 XML 数据的查询和

    2024年02月12日
    浏览(26)
  • WPF上位机9——Lambda和Linq

    2024年02月14日
    浏览(28)
  • AI面试官:LINQ和Lambda表达式(三)

    当面试官面对C#中关于LINQ和Lambda表达式的面试题时,通常会涉及这两个主题的基本概念、用法、实际应用以及与其他相关技术的对比等。以下是一些可能的面试题目,附带简要解答和相关案例和代码: 解答:延迟执行是指LINQ查询在遍历结果之前不会立即执行,而是在实际需

    2024年02月16日
    浏览(24)
  • AI面试官:LINQ和Lambda表达式(一)

    当面试官面对C#中关于LINQ和Lambda表达式的面试题时,通常会涉及这两个主题的基本概念、用法、实际应用以及与其他相关技术的对比等。以下是一些可能的面试题目,附带简要解答和相关案例和代码: 解答:LINQ(Language Integrated Query)是一种在C#编程语言中集成的查询技术,

    2024年02月15日
    浏览(27)
  • AI面试官:LINQ和Lambda表达式(二)

    当面试官面对C#中关于LINQ和Lambda表达式的面试题时,通常会涉及这两个主题的基本概念、用法、实际应用以及与其他相关技术的对比等。以下是一些可能的面试题目,附带简要解答和相关案例和代码: 解答:Lambda表达式的闭包是指它可以访问其周围范围内的变量,即使这些变

    2024年02月16日
    浏览(28)
  • C# Linq 学会使用,学会自己编写Linq

    Linq我暂时理解为,一种内置的非常方便的数据查询的工具 我们先学习它的使用 //数据类 //新建了一个List数据,用来测试数据查询  //现在定义一个需求,需要查出 id2 的数据 引用Linq的命名空间  引用命名空间之后,我们的list对象,拥有了一个扩展方法,Where (扩展方法,在之前的博客

    2024年02月06日
    浏览(32)
  • C# Linq 详解二

    目录 概述 七、OrderBy  八、OrderByDescending 九、Skip 十、Take 十一、Any 十二、All C# Linq 文档(一) 1.Where,2.Select,3.GroupBy,4.First / FirstOrDefault,5.Last / LastOrDefault C# Linq 文档(二) 1.OrderBy ,2.OrderByDescending,3.Skip,4.Take,5.Any,6.All C# Linq 文档(三) 1.Sum / Min / Max / Average,2.Dist

    2024年02月16日
    浏览(30)
  • C# Linq 详解四

    目录 概述 二十、SelectMany 二十一、Aggregate 二十二、DistinctBy 二十三、Reverse 二十四、SequenceEqual 二十五、Zip 二十六、SkipWhile  二十七、TakeWhile C# Linq 文档(一) 1.Where,2.Select,3.GroupBy,4.First / FirstOrDefault,5.Last / LastOrDefault C# Linq 文档(二) 1.OrderBy ,2.OrderByDescending,3.Skip,

    2024年02月16日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包