焦作做网站推广,活动营销方案,富顺网站建设,摄影摄像网站建设总目录 前言
在C#编程中#xff0c;Lambda表达式是一种简洁而强大的语法特性#xff0c;它提供了一种更加灵活和直观的方式来编写匿名函数。无论是在LINQ查询、事件处理还是异步编程中#xff0c;Lambda表达式都扮演着重要角色。本文将详细介绍Lambda#xff0c;帮助您更好…总目录 前言
在C#编程中Lambda表达式是一种简洁而强大的语法特性它提供了一种更加灵活和直观的方式来编写匿名函数。无论是在LINQ查询、事件处理还是异步编程中Lambda表达式都扮演着重要角色。本文将详细介绍Lambda帮助您更好地理解和掌握这一重要的C#特性。 一、Lambda 表达式 是什么
1. 定义
Lambda表达式是C# 3.0引入的一个新特性它是匿名方法的简化形式允许开发者以更简洁的方式定义函数。Lambda表达式可以用于任何需要委托的地方并且可以在运行时动态创建函数对象。它的主要优点包括代码简洁、易于阅读和维护。
2. 基本语法
Lambda表达式的语法非常简单由参数列表、符号和表达式或语句块组成。其基本形式如下
(parameters) expression或
(parameters) { statements }参数列表可以包含零个或多个参数用逗号分隔。符号称为“goes to”操作符表示从参数到表达式或语句块的映射。表达式或语句块可以是一个简单的表达式或一个包含多条语句的代码块。
二、如何使用 Lambda 表达式
根据是否包含语句块Lambda表达式可以分为两种类型表达式Lambda 和 语句Lambda。
1. 使用 表达式Lambda
表达式Lambda是最简单的形式仅包含一个表达式表达式Lambda 侧重于表达式的返回值。其语法如下
(parameters) expression//如x x * 41演化过程
public int Square(int num)
{return num * num;
}上面定义一个简单的计算方法现在我们需要以 Lambda 表达式表现出来该如何表现呢
Funcint, int func x x * x;上述两个示例代码是等效的 x x * x; 本质上等同于将一个有返回值的方法赋予了Func委托
2示例
// 定义一个委托类型
Funcint, int square x x * x;// 调用委托
Console.WriteLine(square(5)); // 输出: 25在这个例子中我们定义了一个名为 square 的委托它接受一个整数参数并返回该整数的平方值。通过Lambda表达式我们可以非常简洁地实现这一功能。
2. 语句Lambda
语句Lambda允许包含多条语句适用于需要执行复杂逻辑的情况。其语法如下
(parameters) { statements }语句Lambda侧重语句块中执行内容具体示例如下
// 定义一个委托类型
Actionint printAndSquare x
{Console.WriteLine($Input: {x});Console.WriteLine($Square: {x * x});
};// 调用委托
printAndSquare(5); // 输出: Input: 5 Square: 25在这个例子中我们定义了一个名为 printAndSquare 的委托它接受一个整数参数并打印输入值及其平方值。通过语句Lambda我们可以轻松实现这一复杂的逻辑。
Funcint, int factorial n
{if (n 0)return 1;elsereturn n * factorial(n - 1);
};3. Lambda 表达式的各种使用方式
1无参数 与 空括号
将 lambda 表达式的输入参数括在括号中。 使用空括号指定零个输入参数。如果是没有参数必须有这个空括号
Action line () Console.WriteLine();2方法体只有一行代码
如果方法体中只有一行代码可以省略方法体大括号
Action line1 () { Console.WriteLine(test); };//省略方法体大括号
Action line2 () Console.WriteLine(test);3类型推断
C# 编译器会根据上下文自动推断参数类型无需显式声明 Lambda表达式的类型是由编译器根据上下文推断出来的通常对应于某个委托类型如 FuncT, TResult 或 ActionT。如果Lambda表达式没有返回值则其类型为 Action如果有返回值则其类型为 Func。 Funcint, int, int func3 (int num1, int num2) num1 * num2;//类型推断 允许我们省略 数据类型的显示声明
Funcint, int, int func4 (num1, num2) num1 * num2;4无法类型推断时
一般情况下编译器可自行推断输入参数的类型但存在编译器无法推断的情况则需自行指定
Funcint, string, bool isTooLong (int x, string s) s.Length x;5省略return
如果方法体中只有一行代码且有返回值可以省略return
当方法体中只有一行代码但并没有返回值的时候此时的Lambda表达式 是 【语句 Lambda】当方法体中只有一行代码且有返回值的时候此时的Lambda表达式 是 【表达式 Lambda】
// 语句 Lambda 侧重于执行内容
Action action () Console.WriteLine(ss);// 表达式 Lambda侧重于返回值
// 特征一行代码 有返回值
Funcint, int func1 x x * x * x;
Funcint, string func2 x x.ToString();
6一个参数
如果只有一个输入参数则括号可有可无
Funcint, int func (x) x * x * x;//省略括号
Funcdouble, double cube x x * x * x;7 2个参数以上
两个或更多输入参数使用逗号加以分隔
Funcint, int, bool testForEquality (x, y) x y;Funcint, int, int add (x, y) x y;8多行代码 显示 return
当方法体中具有多行代码则 该Lambda表达式 是【语句Lambda】如果需要返回数据则需要显示使用return。
Funcint, int, int func3 (num1, num2)
{Console.WriteLine(计算);return num1* num2;
};
三、Lambda 表达式的常见应用场景
1. 应用场景
Lambda表达式广泛应用于各种场景以下是几个常见的应用场景
LINQ查询在LINQ查询中Lambda表达式常用于指定过滤条件、投影、排序等操作。事件处理可以用Lambda表达式来简化事件处理程序的编写。异步编程在异步编程中Lambda表达式可用于定义异步任务的执行逻辑。委托与回调Lambda表达式可以作为委托的实现用于回调函数或其他需要传递函数指针的场合。
2. 应用场景示例
1Lambda与委托
内置委托类型 Lambda表达式可隐式转换为Func或Action委托// Func委托带返回值
Funcint, int, int add (a, b) a b; // Action委托无返回值
Actionstring log msg Console.WriteLine(msg); Lambda 表达式可以转换的委托类型由其参数和返回值的类型定义。 如果 Lambda 表达式不返回值则可以将其转换为 Action 委托类型之一否则可将其转换为 Func 委托类型之一。 自定义委托 Lambda可直接赋值给自定义委托类型delegate int Operation(int a, int b);
Operation add (x, y) x y;
Console.WriteLine(add(3, 4)); // 输出 72Lambda 在LINQ中的应用
Lambda是LINQ查询的基石是编写查询条件的标准方式用于定义筛选、排序和转换逻辑
var numbers new Listint { 1, 2, 3, 4, 5 };
// 筛选大于3的元素
var filtered numbers.Where(n n 3); // 筛选 3 的数
// 转换为平方值
var squares numbers.Select(n n * n); // 转换为平方值public class Program
{public static void Main(){var numbers new Listint { 1, 2, 3, 4, 5 };// 筛选var evenNumbers numbers.Where(x x % 2 0);Console.WriteLine(Even numbers: string.Join(, , evenNumbers));// 排序var sortedNumbers numbers.OrderBy(x x);Console.WriteLine(Sorted numbers: string.Join(, , sortedNumbers));// 投影var squaredNumbers numbers.Select(x x * x);Console.WriteLine(Squared numbers: string.Join(, , squaredNumbers));}
}表达式树Lambda还可生成表达式树供LINQ to SQL等框架解析为SQL语句。
3 Lambda 在事件处理中的应用
Lambda 可简化事件处理程序的编写
button.Click (sender, e) Console.WriteLine(按钮被点击);4Lambda 在异步编程中的应用
在异步编程中Lambda表达式可以用于定义异步任务的执行逻辑。
class Program
{static async Task Main(){await Task.Run(() {Console.WriteLine(Task started.);for (int i 0; i 5; i){Console.WriteLine($Processing item {i 1});}Console.WriteLine(Task completed.);});Console.WriteLine(Main method completed.);}
}在这个例子中我们使用Lambda表达式 () { ... } 来定义异步任务的执行逻辑。
三、高级特性
1. 闭包Closure
Lambda 表达式可以捕获上下文中(或 外部作用域 )的变量形成闭包。 Lambda表达式可以捕获其定义范围内的局部变量这意味着Lambda表达式可以访问外部作用域中的变量。这种特性使得Lambda表达式在某些情况下非常强大和灵活。 public class Program
{public static void Main(){int factor 2;Funcint, int multiply x x * factor;Console.WriteLine(multiply(5)); // 输出: 10factor 5;Console.WriteLine(multiply(5)); // 输出: 25闭包保留了 factor 的引用}
}在这个例子中Lambda表达式捕获了外部变量 factor 并在计算结果时使用了这个变量的值。
需要注意的是被捕获的变量在Lambda表达式被调用时仍然有效因此要确保这些变量在其生命周期内不会被销毁或修改。
注意事项
捕获的变量生命周期与委托绑定可能导致内存泄漏避免修改外部变量防止逻辑混乱。闭包可能导致意外的变量共享需谨慎处理。
2. 表达式树Expression Tree
Lambda 表达式可以转换为表达式树用于表示代码的结构化形式。表达式树常用于动态生成代码或进行反射操作。
public class Program
{public static void Main(){ExpressionFuncint, int expression x x 1;Console.WriteLine(expression.ToString()); // 输出: x (x 1)}
}3. 异步 Lambda
Lambda 表达式可以用于异步操作通过 async 和 await 关键字实现。
FuncTaskint asyncLambda async () await Task.Delay(1000).ContinueWith(_ 42);using System;
using System.Threading.Tasks;public class Program
{public static void Main(){Funcint, Taskint asyncLambda async x {await Task.Delay(1000);return x * x;};asyncLambda(5).ContinueWith(t Console.WriteLine(t.Result)); // 输出: 25}
}FuncTask asyncTask async ()
{ await Task.Delay(1000); Console.WriteLine(异步完成);
}; 4. 动态方法
Lambda 表达式可以用于动态生成方法这在反射或动态调用中非常有用。
using System;
using System.Reflection.Emit;public class Program
{public static void Main(){// 动态生成一个方法DynamicMethod dynamicMethod new DynamicMethod(Add, typeof(int), new[] { typeof(int), typeof(int) }, typeof(Program).Module);ILGenerator il dynamicMethod.GetILGenerator();il.Emit(OpCodes.Ldarg_0);il.Emit(OpCodes.Ldarg_1);il.Emit(OpCodes.Add);il.Emit(OpCodes.Ret);// 调用动态生成的方法Funcint, int, int add (Funcint, int, int)dynamicMethod.CreateDelegate(typeof(Funcint, int, int));Console.WriteLine(add(2, 3)); // 输出: 5}
}5. 泛型 Lambda
Lambda 表达式可以用于泛型委托提高代码的复用性增强灵活性。
FuncT, string toString (T obj) obj?.ToString(); 四、注意事项与限制 作用域规则 Lambda 无法捕获 ref/out 参数。Lambda 内的return不影响外部方法。外部方法无法访问 Lambda 内部定义的变量。 运算符限制 不可用于is或as运算符左侧。 语句限制 不允许包含 goto、break、continue 跨越 Lambda 边界的语句。 性能考量 表达式树可能比直接委托生成更多内存开销。频繁调用的Lambda需避免闭包捕获减少GC压力。过度使用Lambda表达式可能影响性能尤其是在循环中频繁创建委托时。Lambda 表达式在运行时会被编译为委托或表达式树可能会有一定的性能开销。在性能敏感的场景中需要谨慎使用。 循环变量捕获 Lambda表达式捕获循环变量时可能会导致意外行为多线程异步情况下。应使用局部变量来避免。 for (int i 0; i 3; i)
{int local i;actions.Add(() Console.WriteLine(local));
}五、演化过程 public delegate void ShowDelegate(int a,string b);public class LambdaEvolution{public void Show(int a1,string b1){Console.WriteLine($show{a1}:{b1});}public void Test(){//1 .Netframework1.0/1.1原始方法ShowDelegate showDelegate new ShowDelegate(Show);//2 .NetFramework2.0匿名方法增加delegate,去掉单独定义方法showDelegate delegate (int x,string y) { Console.WriteLine($show{x}:{y}); };//3 .NetFramework3.0 引入Lambda表达式去掉delegateshowDelegate (int s,string t) { Console.WriteLine($show{s}:{t}); };//4 .NetFramework3.0后期简化参数类型,编译器自动推断数据类型showDelegate (s,t) { Console.WriteLine($show{s}:{t}); };//5 如果方法体中只有一行代码可以省略方法体大括号showDelegate (s,t) Console.WriteLine($show{s}:{t});//如果方法只有一个参数可以省略参数小括号Actionstring action x Console.WriteLine($show{x});//如果方法体中只有一行代码且有返回值可以省略returnFuncint, string func x x.ToString();}} 结语
回到目录页C#/.NET 知识汇总 希望以上内容可以帮助到大家如文中有不对之处还请批评指正。