c#笔记之lambda表达式和linq

学习前置(大概了解就可以):

匿名方法 是 C# 中一种没有名字的方法 ,它允许你直接内联定义代码块 ,无需单独声明方法名,主要用于简化委托(Delegate)的使用,是 Lambda 表达式的前身。

一、核心概念

  1. 依赖委托:匿名方法必须绑定到委托类型使用,不能单独存在;
  2. 无方法名:只有方法体,没有方法名称;
  3. 简化代码:无需单独定义独立方法,适合一次性、简短的逻辑。

格式:

cs 复制代码
// 委托定义(匿名方法必须依附委托)
委托类型 委托变量 = delegate(参数列表) 
{
    // 方法体逻辑
};

例子

cs 复制代码
// Action:无参数无返回值
Action print = delegate() { Console.WriteLine("内置委托+匿名方法"); };

// Func:带参数有返回值
Func<int, int, int> multiply = delegate(int a, int b) { return a * b; };

Lambda学习内容:

Lambda 表达式是简化版的匿名方法 ,用来快速定义可传递的代码块(委托 / 表达式树),是 C# 中最常用的语法之一,广泛用于 LINQ 查询、事件、委托、异步编程等场景。


一、Lambda核心概念

  1. 本质:没有方法名的微型方法
  2. 符号=> 读作 goes to / 变成
  3. 作用:代替冗长的委托 / 匿名方法写法,让代码更简洁
  4. 依赖 :必须配合委托 (如 ActionFunc)或 LINQ 使用

二、Lambda基本格式

cs 复制代码
(参数,参数) => 
{ 
要做的事;
}

可以写在一行

(参数,参数,参数) => { 要做的事; }



参数多少主要看委托,而且系统可以从委托里推导出参数的类型所以参数类型也可以不写
比如(int x,int b)=>{};可以写成(a,b)=>{}


可以简化很多东西
Func<int, int> f = new Func<int, int>((int x) => { return x + 1; });

第 1 步:去掉 new Func<int, int> 构造
委托可以直接赋值匿名方法 / Lambda,不需要手动 new
Func<int, int> f = (int x) => { return x + 1; };

第 2 步:去掉参数类型 int
编译器能从委托 Func<int, int> 推导出 x 是 int
Func<int, int> f = (x) => { return x + 1; };

第 3 步:单个参数去掉括号
只有一个参数时,(x) 可以写成 x
Func<int, int> f = x => { return x + 1; };

最后一步:单行表达式去掉大括号和 return
Lambda 右边只有一行返回语句时:去掉 { },去掉 return,去掉末尾分号
Func<int, int> f = x => x + 1;



可以看到省略之后的x=>x+1没有;
​
因为省略之前的lambda是作为一个完整的方法体;
省略之后的lambda表达式只是作为一个参数;new Func<int, int>( 这里面是参数 );
就像正常方法里正常语句里的参数一样

void Add(int x)
{
}

调用方法 Add(1+5);这里的1+5就是表达式不用加;变成Add(1+5;);




​

2.1. 无参数 Lambda

cs 复制代码
// 完整写法
Action test = () => { Console.WriteLine("Hello Lambda"); };

// 只有一行代码时,大括号可以省略
Action test2 = () => Console.WriteLine("Hello Lambda");


//自定义委托
 public delegate void Test();
  Test tt = new Test(() => { Console.WriteLine("Hello Lambda"); });
  tt();

2.2. 带参数 和返回值Lambda

cs 复制代码
// 单行表达式:自动返回结果,不用写 return
Func<int, string> intToString = num => num.ToString();
//多参数保留()
Func<int, int,string> intToString = (num ,num1)=> num.ToString();


// 多行代码:必须写 return + 大括号
Func<int, int> calc = n =>
{
    n += 10;
    return n * 2;
};



  public delegate int de(int xxx, int x);
  de d = new de((int a, int b) =>
  {
      Console.WriteLine(a + b);
      return a + b;

  });

2.3带参数无返回值

cs 复制代码
 Action<string, int> aa = new Action<string, int>(( x,  b) => {
     
     Console.WriteLine(x+b); });

 aa("sss", 5);

一个比较复杂的例子用到了泛型委托;

cs 复制代码
static async Task Main(string[] args)
{
    Add((int a,int b) => { 
        Console.WriteLine(a*b);
        return a * b; },7,8);
   

}
      
static void Add<T>(Func<T,T,T> func,T A,T B )
{
    func(A, B);
}

三、Linq

3.1 linq是什么

LINQ(Language Integrated Query,语言集成查询) 是 C# 中最核心、最实用 的功能之一,它让你可以用类似 SQL 的语法直接查询、过滤、排序、聚合各种数据(数组、集合、数据库、XML 等),无需编写复杂的循环逻辑。

3.2 linq里的lambda为什么不用;

有一个疑问就是同样是lumbda表达式为什么在委托里加;但是linq查询里不用;

cs 复制代码
// 多行代码的时候可以看到lambda表达式的语句里要加;
Func<int, int> calc = n =>
{
    n += 10;
    return n * 2;
};


// 这里去掉()之后已经初见端倪了这里的;也不是加个lambda的是加给整个语句的
Func<int, string> intToString = num => num.ToString();


linq的时候lambda表达式作为参数没有;
var query2 = students.Where(s => s.Age == 20);

因为linq里的lambda表达式只是作为一个参数;就像正常方法里正常语句里的参数一样

cs 复制代码
void Add(int x)
{
}

调用方法 Add(1+5);这里的1+5就是表达式不用加;变成Add(1+5;);

3.3常用方法

首先创建一个list

cs 复制代码
// 学生实体类
public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string ClassName { get; set; }
    public int Score { get; set; }
}

// 测试数据
List<Student> students = new List<Student>
{
    new Student{Id=1, Name="张三", Age=18, ClassName="一班", Score=90},
    new Student{Id=2, Name="李四", Age=19, ClassName="一班", Score=85},
    new Student{Id=3, Name="王五", Age=18, ClassName="二班", Score=95},
    new Student{Id=4, Name="赵六", Age=20, ClassName="二班", Score=78},
    new Student{Id=5, Name="钱七", Age=19, ClassName="三班", Score=88}
};

3.3. 1. 过滤,筛选:Where(最常用)

注意这里查出来之后x并不是list或者Stundent类;而是IEnumerable<Student>这只是一个「待执行的查询规则」 ,不是真正装满数据的集合。只是记录了你要筛选 "年龄 = 18" 的学生这个条件。

因为linq是可以拼接的可以在这个语句后面加students.Where(...).OrderBy(...).Select(...),每一步都不执行,最后一次性执行,性能更高

cs 复制代码
//查询Age大于等于19岁的
 var x=  stu.Where(s => s.Age >= 19);

// 多条件:一班 且 分数>85
var list2 = students.Where(s => s.ClassName == "一班" && s.Score > 85);

如果这时候要满足结果的list加个tolist方法
// 这才是真正的 List<Student>
List<Student> x= stu.Where(s => s.Age >= 19).ToList();

3.3.2 select 提取

select也是筛选和where的区别:

1.select是提取对象的具体一个东西,where是一堆对象里筛选合格的对象

2.想 删数据、留一部分 → 用 Where,想 改数据、转格式、取字段 → 用 Select

cs 复制代码
//获取所有学生的 姓名列表(只要名字,不要其他信息)
var x = stu.Select(s => s.Name).ToList();


select还可以新建对象,格式是.select(顺便的参数名字=> new{ 名字1=顺便的参数名字.属性,名字1=顺便的参数名字.属性 });
✅ 一个临时的、自动生成的类的对象
✅ 没有名字的类(所以叫 "匿名")
✅ 编译器自动帮你创建,你不用写 class 定义
✅ 只读对象(创建后不能改里面的值)

//找出 二班 的学生,并且只返回姓名和分数
var x = stu.Where(s=>s.ClassName=="二班").Select(s => new { mz=s.Name, fs=s.Score }).ToList();

x得到的就是一个类的list里面的类只有两个属性mz和fs

可以写成下面这样比较好理解new的格式,因为是系统生成没面子的类所以直接是new {}中间没有名字,
还有就是为什么是,"mz=s.Name,"还是因为是参数,看下面完整的例子比较好理解
  var x = stu.Where(s=>s.ClassName=="二班").Select(s => new  Student{ Name=s.Name, Score=s.Score }).ToList();


//返回所有学生的 姓名 +成绩等级等级:≥90 = 优秀,否则 = 普通

var x = stu.Select(s => new { mz= s.Name,dj=s.Score>=90?"优秀":"普通"}).ToList();

3.3.3排序OrderBy

OrderBy → 从小到大, OrderByDescending → 从大到小;

cs 复制代码
// 单字段排序
var sorted = products.OrderBy(p => p.Price);
var sortedDesc = products.OrderByDescending(p => p.Price);
// 多字段排序
var multiSorted = products
    .OrderBy(p => p.Category)      // 先按分类升序
    .ThenByDescending(p => p.Price); // 再按价格降序

// 反转顺序
var reversed = products.Reverse();

3.3.4GroupBy = 分组

作用:把数据按照某个特征(比如班级、性别、年龄)分成一堆一堆的

最常用场景:按班级统计人数、算平均分、求最高分

cs 复制代码
  List<Student> stu = new List<Student>
  {
      new Student{Id=1, Name="张三", Age=18, ClassName="一班", Score=90},
      new Student{Id=2, Name="李四", Age=19, ClassName="一班", Score=85},
      new Student{Id=3, Name="王五", Age=18, ClassName="二班", Score=95},
      new Student{Id=4, Name="赵六", Age=20, ClassName="二班", Score=78},
      new Student{Id=5, Name="钱七", Age=19, ClassName="三班", Score=88}
  };

//按【班级】分组
var group = stu.GroupBy(s => s.ClassName).ToList();

// group 的类型是:IEnumerable<IGrouping<string, Product>>;
不是 List<T>,也不是 Dictionary<TKey, List<T>> ;可以理解为有
两个东西一个是key这个属性还有一个就是符合这个key的数据集合;比如
第一个key是一班,集合里就是张三和李四这两个对象

可以靠 var i = group [0].Key;获取第一个标签 ,
var i = group [0].Tolist();把符合第一个标签的集合变成list


// 万能模板
var result = source
    .GroupBy(x => x.KeyProperty)           // 分组
    .Select(g => new                        // 投影
    {
        Key = g.Key,
        Count = g.Count(),
        Sum = g.Sum(x => x.ValueProperty),
        Items = g.ToList()//这就是把符合第一个标签的集合变成list
    });

3.3.5常见数学计算

  • Count() → 统计数量
  • Sum() → 求和
  • Average() → 平均
  • Max() / Min() → 最大 / 最小

都可以加入判断比如下面的求平均年龄可以加一个只对年龄大于19的求

cs 复制代码
      var x = stu.Count();//list的数量

  var x = stu.Select(s=>s.Age).Sum(); // 总年龄

    var x = stu.Select(s=>s.Age).Average(), // 平年龄
 var x = stu.Select(s=>s.Age).Average(a=>a>19);


        var x = stu.Select(s=>s.Age).Max() // 最高分

3.3.6 Any / All ------ 判断是否存在 / 全部满足

专门用来做条件判断 ,返回的只有:true(是) 或 false(否)

Any = 至少有一个满足 → true

只要有一个符合条件,就返回 true

All = 全部都满足 → true

所有的都必须符合,才返回 true

cs 复制代码
 // 判断 一班 里 有没有人 分数 ≥ 90

 var x = stu.Where(s => s.ClassName == "一班").Any(y => y.Score >= 90);

3.3.7 合并Concat和Union

两个都是合并

  • Concat :直接拼接,保留重复
  • Union :合并 + 自动去重
cs 复制代码
// 合并 list1 + list2
var 全部学生 = list1.Concat(list2).ToList();

linq综合例子

cs 复制代码
//查询 分数大于 85 分 并且 不是二班 的学生。结果按照 年龄降序 排列(大的在前)
。最后只返回:姓名、班级、分数。

var x = stu.Where(s => s.Score > 85 && s.ClassName != "二班")
.OrderByDescending(ss => ss.Age).Select(sss => new { xm = sss.Name, 
bj = sss.ClassName, fs = sss.Score }).ToList();




//按 班级 分组只查询 该班级总人数 >= 2 人 的班级返回:班级名、人数、最高分、
最低分

var x = stu.GroupBy(x => x.ClassName).Where(ss => ss.Count() >= 2)
.Select(sss => new { bj = sss.Key, rs = sss.Count(),
 zg = sss.Max(s => s.Score), zd = sss.Min(s => s.Score) }).ToList();

学习时间:

26.0402

相关推荐
Xudde.2 小时前
班级作业笔记报告0x05
笔记·学习·安全·web安全
_李小白3 小时前
【OSG学习笔记】Day 24: Texture2D 与 Image
android·笔记·学习
猹叉叉(学习版)3 小时前
【系统分析师_知识点整理】 12.系统设计
笔记·软考·系统设计·系统分析师
qq_391105343 小时前
TDengine C# 连接示例和授权管理
大数据·数据库·c#·时序数据库·tdengine
Rain_Rong3 小时前
禁止迅雷11更新
笔记
孙严Pay3 小时前
快捷支付和网关支付,到底有啥不一样?
笔记·科技·计算机网络·其他·微信
prog_61033 小时前
【笔记】用cursor手搓cursor(四)
人工智能·笔记·大语言模型·agent
313YPHU33 小时前
【笔记】Node.js 开发 CLI 工具
笔记
a17798877124 小时前
小程序码的生成与获取码中的scene
小程序·c#