首页 > 其他分享 >CH06_Lambda表达式

CH06_Lambda表达式

时间:2024-11-19 10:47:19浏览次数:3  
标签:委托 C# CH06 int 匿名 表达式 Lambda

第6章:Lambda表达式


本章目标

  1. 为什么要学习C#编程语言

  2. 了解C#相关常识

  3. C#开发工具Visual Studio安装

  4. 掌握C#程序的开发步骤

  5. 掌握C#的注释

  6. 掌握C#的常用转义符

本章内容

lambda表达式演变史

C# 匿名函数的演变历史可以追溯到 C# 语言的不同版本,随着语言特性的不断丰富和发展,匿名函数经历了以下几个主要阶段:

C# 1.0

在 C# 1.0 中,虽然还没有直接支持匿名函数的概念,但已经引入了委托(Delegate)这一关键概念。委托允许将方法作为参数传递或存储为变量,为后续匿名函数的引入奠定了基础。在这个版本中,若要创建委托实例,必须先定义一个具有匹配签名的方法,然后使用该方法的名称来初始化委托。

public delegate int MyDelegate(int x, int y);

public static int AddNumbers(int a, int b)
{
    return a + b;
}

MyDelegate add = new MyDelegate(AddNumbers);

C# 2.0

C# 2.0 引入了匿名方法,这是对匿名函数功能的初步实现。匿名方法允许开发者在需要委托的地方直接编写一段代码块(内联),而无需事先定义一个命名方法。这种语法简化了在特定上下文中临时创建和使用简单功能的过程,特别是在事件处理和回调场景中

MyDelegate fun = delegate(int a, int b)
{
    return a + b;
};

C# 3.0

C# 3.0 引入了更强大的匿名函数形式——Lambda 表达式。Lambda 表达式进一步简化了匿名方法的语法,使其更加简洁且易于阅读。Lambda 表达式可以直接表示输入参数、箭头符号(=>)以及要执行的表达式或语句块。它们在LINQ(Language Integrated Query)中扮演了核心角色,极大地增强了C#的函数式编程能力。

// 单行表达式形式
MyDelegate fun1 = (int a, int b) => a + b;

// 多行语句块形式
MyDelegate fun2 = (int a, int b) =>
{
    int result = a * b;
    Console.WriteLine("Processing numbers...");
    return result;
};

C# 4.0

随着Lambda表达式的普及和广泛使用,匿名方法在新项目中的使用逐渐减少,Lambda表达式成为编写匿名函数的首选方式。后续版本的C#(如4.0、5.0、6.0、7.0、8.0、9.0、10.0等)继续强化和扩展了Lambda表达式的能力,包括:

  • 类型推断:Lambda表达式中的参数类型可以根据上下文自动推断,进一步减少了代码冗余。
  • 可变数量参数:Lambda表达式支持可变数量参数,方便处理不定长度的参数列表。
  • Expression-bodied members:C# 6.0引入了表达式体成员语法,使得Lambda风格的简短表达式可以用于方法、属性、构造函数等更多场景。
  • Local functions(局部函数):虽然不是匿名函数,但C# 7.0引入的局部函数提供了另一种在方法内部定义私有、嵌套函数的方式,有时可以作为匿名函数的替代方案,尤其是在需要复用或避免闭包副作用的情况下。

综上所述,C# 匿名函数的演变历史始于C# 2.0的匿名方法,经由C# 3.0的Lambda表达式实现了重大飞跃,并在后续版本中持续得到增强和完善,成为现代C#编程中不可或缺的一部分。尽管匿名方法在早期版本中有其作用,但在当前实践中,Lambda表达式已成为编写匿名函数的标准方式。

lambda 表达式使用方法

定义描述

Lambda表达式实际上是一种匿名函数,在Lambda表达式中可以包含语句以及运算等操作。并且可用于创建委托或表达式目录树类型,支持带有可绑定到委托或表达式树的输入参数的内联表达式。使用Lambda表达式可大大减少代码量,使得代码更加的优美、简洁,更有可观性。

基本语法
(input-parameters) => { <sequence-of-statements> }

Lambda 表达式的语法由三部分组成:

  1. 参数列表:位于圆括号 () 内,可以为空(表示无参数)、包含一个或多个参数,参数类型可以显式声明或根据上下文推断。

    • 显式类型:(int x, string y)
    • 类型推断:(x, y) —— 当Lambda表达式赋值给已知委托类型或在编译器可以确定类型的情境下,可以省略参数类型。
  2. 箭头操作符 =>:将参数列表与表达式或语句块分隔开。

  3. 表达式或语句块:表示Lambda表达式的行为。

    • 单行表达式:直接返回表达式的计算结果,不需要使用 return 关键字。

    • int[] numbers = { 1, 2, 3 };
      var evenNumbers = numbers.Where(n => n % 2 == 0);
      
      
    • 多行语句块:使用花括号 {} 包围,如果需要执行多条语句或需要显式 return 语句,则使用语句块形式。

    • Func<int, int> squareAndLog = number =>
      {
          int squared = number * number;
          Console.WriteLine($"Squared: {squared}");
          return squared;
      };
      
      
使用场景

作为参数:Lambda 表达式常被用作需要函数作为参数的方法或操作符的参数,如 LINQ 方法、事件处理器、ActionFunc 委托实例化等。

static void Fun1()
{
    List<string> stuList = new List<string> { "孙悟空", "猪八戒", "沙悟净", "唐僧" };

    //使用 Predicate 委托(返回类型为bool)
    var result1 = stuList.Find(p => p.StartsWith("孙"));

    // 使用 Action 委托(无返回值)
    Action<string> logMessage = name => Console.WriteLine($"姓名: {name}");

    // 使用 Func 委托(无返回值)
    Func<int, int, int> add = (a, b) => a + b;
}

匿名委托:Lambda 表达式可以替代传统的匿名方法,创建不需显式定义的、临时使用的委托实例。

static void Fun2()
{
    Button btn = new Button();

    // 传统匿名方法
    btn.Click += delegate (object sender, EventArgs e)
    {
        MessageBox.Show("按钮被点击了!");
    };

    // Lambda 表达式形式
    btn.Click += (sender, e) => MessageBox.Show("按钮被点击了!");

}

事件处理:Lambda 表达式简化了事件处理器的注册,尤其在需要访问外部变量时,可以利用闭包特性 。

static void Fun3()
{
    Button btn = new Button();

    string greeting = "hello!";
    btn.Click += (sender, e) => MessageBox.Show(greeting);

}
注意事项
  • 类型推断:Lambda 表达式的参数类型和返回类型通常可以由编译器推断,无需显式声明。但在某些情况下,可能需要显式提供类型信息以消除歧义。

  • 闭包:Lambda 表达式可以捕获其封闭作用域内的变量,形成闭包。理解闭包行为对于避免潜在的并发问题和资源管理问题至关重要。

  • 性能:Lambda 表达式通常编译为高效代码,但在某些情况下(如大型循环中的复杂Lambda表达式),可能会导致编译器生成额外的类和方法,影响性能。适当优化或使用局部函数替代可能有助于提升效率。

系统自带的两种委托

C# 中的 Action 和 Func 是预定义的泛型委托类型,它们简化了委托的使用,避免了手动声明相似用途的自定义委托。今后我们使用时,没有必要自定义委托了,全部使用系统自带的委托就可以了,方便省事.

Action 委托

Action 代表一个无返回值的方法,只用于封装需要执行的操作。根据需要传递的参数数量,C# 提供了一系列预定义的 Action 类型,从 Action(无参数)到 Action<typeparamref name=“T1”>, …, T16</typeparamref></typeparamref></typeparamref>(最多16个参数)。

static void Fun4()
{
    //无参数
    Action action1 = () => Console.WriteLine("无参.");
    action1(); 

    //带参数
    Action<string, int> paramAction = (name, age) => Console.WriteLine($"{name}, count: {age}");
    paramAction("张三", 18); 

}
Func 委托

Func 代表一个有返回值的方法,除了封装操作外,还返回一个指定类型的值。Func 类型同样有一系列预定义版本,格式为 Func<typeparamref name=“T1”>, …, Tn</typeparamref>, TResult>,其中 T1 到 Tn 代表输入参数类型,TResult 代表返回值类型。

static void Fun5()
{
    //无参,返回整数
    Func<int> func1 = () => DateTime.Now.Second;
    int result1 = func1(); // 获取当前秒数
    Console.WriteLine(result1);

    //带参,返回字符串
    Func<string, int, string> fun2 = (name, age) => $"姓名:{name} ,年龄{age}";
    string result2 = fun2("张三", 30);
    Console.WriteLine(result2);

    Console.WriteLine("-------------------------------------------");

    List<string> stuList = new List<string> { "孙悟空", "猪八戒", "沙悟净", "唐僧", "孙尚香" };

    //查询满足要求元素的数量
    var count = stuList.Count(f=> f.StartsWith("孙"));

    //查询满足要求的元素
    stuList.Where(f=> f.StartsWith("孙"));

    Console.WriteLine("-------------------------------------------");

    List<Student> stuList2 =new List<Student> {
        new Student{Name="孙悟空",Age=500 },
        new Student{Name="猪八戒",Age=400 },
        new Student{Name="沙悟净",Age=300 },
        new Student{Name="唐僧",Age=800 },
        new Student{Name="孙尚香",Age=200 }
    };

    //最大值
    var max = stuList2.Max(f => f.Age);

    //最小值
    var min = stuList2.Min(f => f.Age);

    //平均值
    var avg = stuList2.Average(f => f.Age);

    //总和
    var sum = stuList2.Sum(f => f.Age);
}
Predicate 委托

Predicate泛型委托:表示定义一组条件并确定指定对象是否符合这些条件的方法。此委托由 Array 和 List 类的几种方法使用,用于在集合中搜索元素。

static void Func6()
{
    List<string> stuList = new List<string> { "孙悟空", "猪八戒", "沙悟净", "唐僧","孙尚香" };

    //所搜满足要求的第一个元素
    var name= stuList.Find(p=> p.StartsWith("孙"));

    //所搜满足要求的所有元素
    var names = stuList.FindAll(p=> p.StartsWith("孙"));

    所搜满足要求的第一个元素的索引
    var index= stuList.FindIndex(p => p.StartsWith("孙"));

}

本章总结

总之,C# Lambda 表达式提供了简洁、直观的方式来编写匿名函数,极大地提高了代码的可读性和可维护性,尤其在处理函数式编程、事件处理、委托、LINQ 查询等方面发挥着重要作用。理解和熟练运用Lambda表达式是现代C#开发中的重要技能。

课后作业

学生类:
姓名
年龄
性别
身高

有一个学生集合,要求用lambda表达式实现以下功能:

1.查询所有姓“张”的学生。
2.查询所有姓“张”的男生
3.查询平均身高并返回
4.查询已成年的男生
5.查询身高不低于160cm的女生
6.查询女生的平均年龄,并返回。
7.查询身高不低于170cm的男生的数量
8.查询升高不低于170cm或年龄不低于18的学生

标签:委托,C#,CH06,int,匿名,表达式,Lambda
From: https://blog.csdn.net/m0_37631902/article/details/143874981

相关文章

  • pandas中,对某列应用正则表达式
    1.str.contains(),类似re.search(),检查是否包含特定字符串importpandasaspd#示例数据data={'col1':['apple','banana','cherry','pineapple','grape']}df=pd.DataFrame(data)#查找包含字母'a'的行pat......
  • 逆波兰表达式求值——栈与队列
    首先是第一次的代码classSolution{public:intevalRPN(vector<string>&tokens){stack<longlong>str;for(inti=0;i<tokens.size();i++){if(tokens[i]!="+"&&tokens[i]!=......
  • MySQL进阶:深入索引 - 函数和表达式索引
    ......
  • 常用正则表达式
    目录#校验数字的表达式数字:^[0-9]*$n位的数字:^\d{n}$至少n位的数字:^\d{n,}$m-n位的数字:^\d{m,n}$零和非零开头的数字:^(0|[1-9][0-9]*)$非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(\.[0-9]{1,2})?$带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})$正数、负数、和小数......
  • javascript-表达式与操作符
    1.数组初始化二维数组letmatrix=[[1,2,3],[4,5,6],[7,8,9]];未定义元素undefinedletsparseArray=[1,,,,5];包含三个未定义元素2.对象初始化letp={x:2.3,y:-1.2};点对象包含x,y坐标letq={};空对象q.x=2.3;q.y=-1.2;赋值3.函数letsquare=function(x){returnx*x;};......
  • cron表达式
    一、Cron表达式0/10****?这种表达式称为cron表达式,通过cron表达式可以灵活的定义出符合要求的程序执行的时间。Cron表达式支持到7个域。cron表达式分为7个域,之间使用空格分隔。其中最后一个域(年)可以为空,每个域都有自己允许的值和一些特殊字符构成。使用这些特殊字......
  • map 和 lambda 函数
    map和lambda的用法及规则1.map函数map是Python内置函数,用于对可迭代对象中的每个元素应用一个函数,并返回一个map对象(可以转换为其他数据类型,如列表、元组等)。语法map(function,iterable,...)参数function:需要应用的函数。iterable:一个或多个可迭代对象。......
  • C# 表达式树 ---- 系列教程
    C#表达式树从0学习表达式树。作者:痴者工良地址:https://ex.whuanle.cn作者博客:http://www.whuanle.cn1.表达式树基础2.基础知识3.变量、常量、赋值4.五类运算符的表达5.判断语句6.循环控制7.值类型、引用类型、泛型、集合、调用函数  出处:C#表达式树......
  • C++ lambda 表达式与「函数对象」(functor)
    C++lambda表达式与「函数对象」(functor)Created:2024-06-27T16:29+08:00Published:2024-11-17T17:01+08:00Categories:C-CPPfunctor(FunctionObject)首先要介绍的是functor——一个重载了operator()的类,该类的实例可以使用operator()。WhatareC++functorsand......
  • 正则表达式
    正则表达式:regularexpression,很多时候都简写为regex.正则表达式可以校验字符串是否满足一定的规则,并用来校验数据格式的合法性.Java中,正则表达式是以字符串的形式体现的.程序示例:publicclassRegexDemo1{publicstaticvoidmain(String[]args){......