Linq快速入门——Lambda表达式的前世今生
·
Lambda表达式其实并不陌生,他的前生就是匿名函数,所以要谈Lambda表达式,就不得不谈匿名函数,要谈匿名函数,那又要不得不谈委托。
何为委托
委托非常好理解,类似于C++里面的函数指针(指向了一个方法),并且委托约束了待指向方法的签名(由返回类型和参数组成)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 委托Test
{
delegate bool FilterDelegate(int i);
class Program
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 5, 6, 6, 7, 8, 9 };
List<int> newList = MyFilter(array,FilterOdd);
foreach (int item in newList)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
static List<int> MyFilter(int[] array, FilterDelegate filter)
{
List<int> list = new List<int>();
for (int i = 0; i < array.Length; i++)
{
if (filter(i))
{
list.Add(i);
}
}
return list;
}
/// <summary>
/// 偶数
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
static bool FilterEven(int i)
{
return i % 2 == 0;
}
/// <summary>
/// 奇数
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
static bool FilterOdd(int i)
{
return i % 2 == 1;
}
}
}

对于上面这个Demo可以看出,我需要定义了两个方法(FilterOdd,FilterEven),让我的委托变量指向这两个方法。但有时候申明方法很麻烦,还要考虑方法名称不重复,所以对于一些我们只使用一次的方法,完全没有必要单独为其申明,使用匿名方法即可(C# 2.0为程序员提供了匿名方法),大大简化了操作
匿名方法
//例如
delegate void Del(int x);
....
Del d = delegate(int k) { /* ... */ };
所以上面例子小小改动一下即可:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 委托Test
{
delegate bool FilterDelegate(int i);
class Program
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 5, 6, 6, 7, 8, 9 };
//使用匿名方法来求偶数
List<int> newList = MyFilter(array, delegate(int i) {
return i % 2 == 0;
});
foreach (int item in newList)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
static List<int> MyFilter(int[] array, FilterDelegate filter)
{
List<int> list = new List<int>();
for (int i = 0; i < array.Length; i++)
{
if (filter(i))
{
list.Add(i);
}
}
return list;
}
}
}

Lambda表达式特性
- C# 2.0中加入的匿名方法,简化了我们编写事件处理函数的工作,使我们不再需要单独声明一个函数来与事件绑定,只需要使用delegate关键字在线编写事件处理代码。
- 而C# 3.0则更进一步,通过Lambda表达式,我们可以一种更为简洁方式编写事件处理代码,新的Lambda事件处理代码看上去就像一个计算表达式,它使用"=>"符号来连接事件参数和事件处理代码。我可以这样写:SomeEvent += 事件参数 => 事件处理代码;
所以上面代码稍稍修改后,用Lambda表达式来替换匿名方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 委托Test
{
delegate bool FilterDelegate(int i);
class Program
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 5, 6, 6, 7, 8, 9 };
//使用Lambda表达式来求偶数
List<int> newList = MyFilter(array, i => i % 2==0);
foreach (int item in newList)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
static List<int> MyFilter(int[] array, FilterDelegate filter)
{
List<int> list = new List<int>();
for (int i = 0; i < array.Length; i++)
{
if (filter(i))
{
list.Add(i);
}
}
return list;
}
}
}

注意:
- 使用Lambda表达式,"=>"之前为参数列表,如果有多个参数,则不能省略括号,比如:(s,e)=>....
- 如果方法有返回值,并且处理代码只有一行,可以简写成i=>i%2==0,等价于i=>{return i%2==0},反之对于有多行的处理代码,则不能简写,必须写完整,比如:(s,e)=>{...程序代码块...}
我们再来看看System.Linq名称空间下的扩展方法有什么特征:

第一个参数为扩展方法,我已经在前一篇文章《Linq快速入门——扩展方法》里提到了,我不做具体解释了,简单来说创建扩展方法就是这四步:
- 创建一个名为MyHelper的类,约定了此类中的方法均是扩展方法。注意这个类必须是静态类(Static)
- 扩展方法必须是Static静态方法
- 第一个参数为待扩展的类型,前面标注this
- 如果MyHelper在一个类库中,记得对其添加引用并using相关名称空间
对于第二个参数:System.Func<TSource, bool> predicate),我们再来深究下。
Fun<T,TResult> and Action<T>
- Fun<T,TResult>:此委托封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。所以在使用 Func<T, TResult> 委托时,不必显式定义一个封装只有一个参数的方法并且其返回类型TResut的委托。
- Action<T>:此委托封装一个方法,该方法只有一个参数并且不返回值。所以在使用 Action<T> 委托时,不必显式定义一个封装只有一个参数的方法(并且不能返回值)的委托。
所以再对上面的Filter进行改进:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 委托Test
{
//delegate bool FilterDelegate(int i);
class Program
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 5, 6, 6, 7, 8, 9 };
//使用匿名方法来求偶数
//List<int> newList = MyFilter(array, delegate(int i) {
// return i % 2 == 0;
//});
//使用Lambda表达式求偶数
List<int> newList = MyFilter(array, i => i % 2 == 0);
foreach (int item in newList)
{
Console.WriteLine(item);
}更多推荐
所有评论(0)