C# Lambda表达式事例

简介:
C# Lambda表达式事例
Lambda表达式语法看上去真的很别扭,其实它就是便变种的匿名方法。其实你不用去管它的语法为什么是这样,你只要记住规则然后通过编写代码和比较慢慢的去体会就可以了,先来看匿名方法:
yuanl注释:首先使用集合初始化语法建立一个整型列表
List list = new List() { 1, 2, 3, 4, 5, 6, 7 };
//你也可以这样:List<int> list =new List<int>(){1, 2, 3, 4, 5, 6, 7};
//匿名方法的使用如下:
List ddNumbers = list.FindAll(
delegate(int i)
{
return (i % 2) != 0;
}

);//匿名方法到此结束,它的作用是筛选数据

foreach (var oddNumber in oddNumbers)//迭代输出数据
{
//输出奇数
Console.WriteLine(oddNumber);
}
上面的匿名方法,我们必须使用delegate来标注,而且还要保证输入参数的类型匹配,这种语法确实还是让人觉得不舒坦。Lambda表达式是如何简化FindAll()方法的:
List ddNumbers = list.FindAll(i => (i % 2) != 0);
//等价于:List ddNumbers = list.FindAll(i =>{if( (i % 2) != 0){return i;}});
解剖Lambda表达式
i => (i % 2) != 0
Lambda表达式的 => 标记(读作 goes to),它的前面是一个参数列表,后面是一个表达式或表达式块。
很明显,前面的参数列表并没有定义参数的类型(由编译器根据上下文推断出i是一个整型),所以它是隐式的。当然,我们也可以显示定义: (int i)=>(i%2)!=0);
我们这里参数列表只有一个参数,所以那个括号可以被省略。

Lambda表达式块语句形式:

List list = new List { 1,2,3,4,5,6,7};
//因为表达式需要多行代码来处理参数切记表达式块的编写规范
var testList=list.FindAll(i=>{
Console.WriteLine("调用FindAll()");
Console.WriteLine("i的值是{0}",i);
bool isOdd=((i%2)!=0);
Console.WriteLine("是否是奇数:"+isOdd);
return isOdd; //Lambda 必须返回满足某个条件的Bool值
});//注意这里的分号
foreach (var a in testList)//var换作int 同样可以(只要符合类型转换规则就好)
{
Console.WriteLine(a);
}
再看下面的例子
使用 .net 2.0 的匿名方法来搜索字符串数组中包含 a 的字符串数组
static void Main(string[] args)
{
string[] list = new string[] { "abc", "12", "java" };//注意字符串数组的初始化规范
string[] yuanl = Array.FindAll(list,
delegate(string s)
{
return s.IndexOf("a") >= 0;
}
//上面等价于:string[] yuanl = list.FindAll(delegate(string s){ return s.IndexOf("a") >= 0;});
foreach (string str in yuanl)
{
Console.WriteLine(str);
}
Console.ReadLine();//这一句主要不同方式的调试环境
}
使用 .net 3.5 的Lambda表达式来搜索字符串数组中包含 a 的字符串数组
static void Main(string[] args)
{
string[] list = new string[] { "abc", "12", "java" };

string[] ll = Array.FindAll(list, s => (s.IndexOf("a") >= 0));
foreach (string str in ll)
{
Console.WriteLine(str);
}
Console.ReadLine();
}

从上述几个例子我们可以看出:
从代码书写角度,代码可读性角度来说:Lambda表达式 比匿名方法更简单了。
而 Lambda表达式 和 匿名方法都是干的同一件事情,让我们少写一个函数定义。函数的调用和函数的实现在一起完成了。
下面有两个参数的 Lambda表达式例子:
注:别看比较复杂,LINQ中实际把 下述代码中的 delegate ,DoSomeThing 替你做了,所以你写代码的时候只需要写
var t = DoSomeThing(7, 8, (x, y) => x * y); 这么一行。
public delegate T yuanl(T t1, T t2);
class Program
{
private static T DoSomeThing(T t1,T t2, yuanl match)//注意yuanl是一T型的委托类型
{
return match(t1, t2);
}
static void Main(string[] args)
{
var t = DoSomeThing(7, 8, (x, y) => x * y);
Console.WriteLine(t);
Console.ReadLine();
}
}
下面这些写法也是对的(你只需要修改Main函数中的代码,其他地方不需要动):
var t = DoSomeThing(7, 8, (int x, int y) => x * y);
var t = DoSomeThing("7", "8", ( x, y) => x + y);//字符串拼接 
或者我们写一个更复杂的: => 右边是一段语句块。
var t = DoSomeThing(7, 8, (x, y) => { if (x < 5) { return (x + 8) * y; } else { return y; } });
最前面的例子是一个参数的例子,我们就不举一个参数的例子了,下面举一个没有参数的例子:
public delegate void yuananl();
class Program
{
private static void DoSomeThing(yuananl match)
{
match();
}

static void Main(string[] args)
{
DoSomeThing(() => Console.WriteLine("jajaja"));
Console.ReadLine();
}
}

同样的,如果一些事件发生的时候我们只想做一点儿简单的事情的话,那么也可用Lambda表达式来实现:
1: System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
2: timer.Interval = 2000;
3: timer.Tick += (sender, e) => { timer.Stop(); MessageBox.Show("Hello, Lambda Expression!"); };

我们来看一段比较完整的代码并以此结束对Lambda表达式的介绍吧:
1: using System;
2: using System.Collections.Generic;
3: 
4: namespace LambdaExpressionDemo
5: {
6: class Program
7: {//定义一List对象_class
8: private static List<StudentData> _class = null;
9: //初始化该对象
10: static void Initialization()
11: {
12: _class = new List<StudentData>();
13: 
14: _class.Add(new StudentData("ZeroCool", 24, GenderType.Male, 87));
15: _class.Add(new StudentData("Michael", 24, GenderType.Male, 93));
16: _class.Add(new StudentData("Frieda", 22, GenderType.Female, 98));
17: _class.Add(new StudentData("Somebody", 23, GenderType.Male, 81));
18: }
19: 
20: static void Main(string[] args)
21: {
22: Initialization();
23: 
24: if (_class == null || _class.Count == 0)
25: {
26: throw new InvalidOperationException("The system initialization was failed.");//抛出异常
27: }
28: //筛选student数据
29: StudentData studentData = _class.Find(student => student.MathScore >= 90 && student.MathScore < 95);
30: RepresentData(studentData);//打印数据
31: //以下几条亦然
32: studentData = _class.Find(student => student.Name.Equals("ZeroCool", StringComparison.InvariantCultureIgnoreCase));
33: RepresentData(studentData);
34: 
35: studentData = _class.Find(student => student.Age < 23);
36: RepresentData(studentData);
37: 
38: Console.ReadLine();
39: }
40: //打印数据方法
41: static void RepresentData(StudentData student)
42: {
43: if (student == null)
44: {
45: Console.WriteLine("No mached student.");
46: 
47: return;
48: }
49: 
50: Console.WriteLine("Name:\t\t" + student.Name);
51: Console.WriteLine("Age:\t\t" + student.Age);
52: Console.WriteLine("Gender:\t\t" + student.Gender.ToString());
53: Console.WriteLine("Math Score:\t" + student.MathScore);
54: Console.WriteLine();
55: }
56: }
57: 
58: public enum GenderType
59: {
60: Male = 0,
61: Female
62: }
63: 
64: public class StudentData
65: {//注意下面字段、属性的定义规范和关联
66: private string _name = String.Empty;
67: public string Name
68: {
69: get { return this._name; }
70: set { this._name = value; }
71: }
72: 
73: private int _age = 0;
74: public int Age
75: {
76: get { return this._age; }
77: set { this._age = value; }
78: }
79: 
80: private GenderType _gender;
81: public GenderType Gender
82: {
83: get { return this._gender; }
84: set { this._gender = value; }
85: }
86: 
87: private int _mathScore = 0;
88: public int MathScore
89: {
90: get { return this._mathScore; }
91: set { this._mathScore = value; }
92: }
93: //无参元的构造方法
94: public StudentData()
95: {
96: }
97: //带有参元的构造方法
98: public StudentData(string name, int age, GenderType gender, int mathScore)
99: {
100: this._name = name;
101: this._age = age;
102: this._gender = gender;
103: this._mathScore = mathScore;
104: }
105: //定义一委托类型
106: public delegate void EmptyDelegate();
107: 委托变量(对象)挂接一方法
108: EmptyDelegate dl = () => Console.WriteLine();
109: }
110: }

表达式树典型的声明形式是:
1: Func<int, int> func = input => input * input;
2: Expression<Func<int, int>> expression = input => input * input;

我们必须要使用的类型是System.Linq.Expressions命名空间中的Expression<T>,而这个T是定义表达式签名的委托的类型,这种把一个Lambda表达式看做一个数据结构而嵌套在另一个Lambda表达式中的做法使得现在的expression不是一个委托而是表达式树的数据结构了。接下来的问题是我们应该如何使用这个表达式树呢?请看完整的代码:
1: static void Main(string[] args)
2: {
3: Func<int, int> func = input => input * input;
4: Console.WriteLine(func(3).ToString());
5: 
6: Expression<Func<int, int>> expression = input => input * input;
7: Func<int, int> fun = expression.Compile();
8: Console.WriteLine(fun(5).ToString());
9: 
10: Console.ReadLine();
11: }

正因为func是可执行代码而expression是数据,所以在使用方式上也会有所差别的,希望以上这些代码可以很好地让你理解Lambda表达式以及表达式树这两个概念。

最后总结一下:从delegate到lambda的演变

先看一个简单的delegate的例子

public static bool IsOdd(int i)
{
return (i & 1) == 1;//判断输入的数据是否为零
}

public delegate bool NumberTester(int i);//声明一委托类型

public static void PrintMatchingNumbers(int from, int to, NumberTester filter)
{
for (int i = from; i <= to; ++i)
{
if (filter(i))//判断
{
Console.WriteLine(i);//输出不为零的数据
}
}
}
调用时只需要执行:

PrintMatchingNumbers(1, 10, new NumberTester(IsOdd));//调用

等价于:PrintMatchingNumbers(1, 10,IsOdd);

很多情况下,我们只要执行只包含一个方法的代理。于是微软在.net 2.0里给我们提供了更方便的anonymous method,比如上面调用IsOdd的过程就能改写成下面这样:

PrintMatchingNumbers(1, 10, delegate(int i)
{
return (i & 1) == 1;
});

如此就避免了IsOdd的声明。微软提供匿名方法的道理是这样的:既然函数IsOdd只在一个地方被调用,那么直接在调用的地方实现岂不更省事儿。这样可以减少我们开发人员的输入。

接着到了3.0,微软更进了一步,他提出了lambda表达式。C#的lambda表达式是这样定义的:参数=> 表达式。于是,我们的代码变的更短:

PrintMatchingNumbers(1, 10, i=>(i & 1) == 1);

也就是说lambda表达式作为一个函数并当作PrintMatchingNumbers的第三个参数来执行,而这个函数只要符合delegate NumberTester的签名就行。理所当然的,lambda表达式可以附值给一个相同签名的delegate:
NumberTester a =new NumberTester();
a += i=>(i & 1) == 1;//注意这里不时数值运算而是方法挂接,a是委托对象

C# 3.0里甚至可以把声明和初始化以及赋值合到一块儿,简写成:

NumberTester a = i=>(i & 1) == 1;

如果我们把NumberTester声明为泛型的delegate,如下:

public delegate U NumberTester<T, U>(T i);

那么这个泛型的delegate应用就太广泛了,涵盖了一切有一个输入参数和一个返回值的函数,所以直接命名为Func更合适,即:
public delegate U Func<T, U>(T i);

其实上面这个类型正是在.net Framework 3.0 中最重要的命名空间 System.Core里定义的。
这样,就可以写成

Func<int,bool> a = i=>(i & 1) == 1;

下面我们再回过头来看看使用这个delegate的PrintMatchingNumbers,应该作相应的更改

public static void PrintMatchingNumbers(int from, int to, Func<int, bool> filter)
{
for (int i = from; i <= to; ++i)
{
if (filter(i))
{
Console.WriteLine(i);
}
}
}

当然,由于泛型的的引入,此处还可以进一步的把类型抽离出来以表达这个意思:在一个范围内的任意的类型的变量,以指定的方式递增,通过判断打印符合条件的值。也就可以得到算法的复用。

完整的例子:

public delegate U Func<T, U>(T i);

public delegate void Func<T>(ref T i);

static void Main(string[] args)

{

DateTime from = DateTime.Parse("2004/06/01");

DateTime to = DateTime.Parse("2005/01/18");

PrintMatchingT<DateTime>(from, to,

delegate(ref DateTime i) { i = i.AddDays(1); },

delegate(DateTime i) { return (i.Month + i.Day == 11);});

Console.WriteLine();

Console.Read();

}

public static void PrintMatchingT<T>(T from, T to, Func<T> incre, Func<T, bool> filter) where T : IComparable<T>
{
for (T i = from; (i.CompareTo(to) < 0); incre(ref i))
{
if (filter(i))
{
Console.WriteLine(i);
}
}
}

这个例子是在指定的时间范围内以天为递增量,判断代表月与日的数字加起来为11的日子。当然具体到这个例子,我们也能把bool改成泛型的,只要保证实际传入的类型能够有效的转化成bool类型的,不然filter(i)是没法放到 if判断中的。
由此可见:混合使用泛型和匿名代理是可以写出很精简的代码,当然这也往往意味着需要写更多的注释来说明你的意图。 









本文转自 xchsp 51CTO博客,原文链接:http://blog.51cto.com/freebird/490291,如需转载请自行联系原作者

目录
相关文章
|
开发框架 .NET 编译器
C# 10.0中Lambda表达式的改进:更简洁、更灵活的代码编写体验
【1月更文挑战第21天】随着C#语言的不断发展,Lambda表达式作为一种简洁、高效的函数式编程工具,在C# 10.0中迎来了重要的改进。本文将详细探讨C# 10.0中Lambda表达式的新特性,包括参数类型的推断增强、自然类型的Lambda参数以及Lambda表达式的属性改进等。这些改进不仅简化了Lambda表达式的编写过程,还提升了代码的可读性和灵活性,为开发者带来了更优质的编程体验。
|
开发框架 自然语言处理 .NET
C#一分钟浅谈:LINQ 查询表达式的使用技巧
【9月更文挑战第6天】LINQ(Language Integrated Query)是C#开发中的强大工具,使查询数据集合变得简单且接近自然语言。本文从基础入手,通过具体示例讲解LINQ查询表达式的使用技巧,包括过滤、排序和分组等操作。同时,文章还探讨了常见问题及解决方法,如性能优化、过早枚举和类型转换等,帮助开发者写出更高效、易维护的代码。
272 16
|
C#
C#一分钟浅谈:Lambda 表达式和匿名方法
本文详细介绍了C#编程中的Lambda表达式与匿名方法,两者均可用于定义无名函数,使代码更简洁易维护。文章通过基础概念讲解和示例对比,展示了各自语法特点,如Lambda表达式的`(parameters) =&gt; expression`形式及匿名方法的`delegate(parameters)`结构。并通过实例演示了两者的应用差异,强调了在使用Lambda时应注意闭包问题及其解决策略,推荐优先使用Lambda表达式以增强代码可读性。
213 8
|
SQL 开发框架 前端开发
在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式
在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式
C#动态查询:巧用Expression组合多条件表达式
在C#中,利用`Expression`类和`AndAlso`、`OrElse`方法,可以组合两个`Expression&lt;Func&lt;T, bool&gt;&gt;`以实现动态多条件查询。该方法通过构建表达式树,方便地构建复杂查询。示例代码展示了如何创建表达式树,分别检查年龄大于等于18和姓名为&quot;John&quot;的条件,并使用`AndAlso`组合这两个条件,最终编译为可执行的委托进行测试。
693 1
|
SQL 开发框架 .NET
C#linq表达式的应用
C#linq表达式的应用
116 0
|
开发框架 .NET 编译器
C# 9.0中的目标类型新表达式:类型推断的又一进步
【1月更文挑战第16天】C# 9.0引入了目标类型新表达式,这是类型推断功能的一个重要扩展。通过目标类型新表达式,开发者在创建对象时可以省略类型名称,编译器会根据上下文自动推断所需类型。这一特性不仅简化了代码编写,还提高了代码的可读性和维护性。本文将详细介绍目标类型新表达式的语法、使用场景及其对C#编程的影响。
|
机器学习/深度学习 开发框架 .NET
C# 中的 Lambda 表达式:一种简洁而强大的编程工具
【1月更文挑战第6天】在现代编程中,Lambda 表达式已经成为一种非常流行的编程范式。C# 作为一种功能强大的、面向对象的编程语言,自然也不例外。Lambda 表达式在 C# 中提供了一种简洁、灵活的方式来表示匿名函数。这些函数可以被用作委托或表达式树类型,从而在各种不同的上下文中使用。
|
开发框架 .NET 编译器
C#学习相关系列之匿名方法和Lambda表达式
C#学习相关系列之匿名方法和Lambda表达式
137 0
|
2月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
190 19