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表达式来替换匿名方法:
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;
}
}
}
注意:
我们再来看看System.Linq名称空间下的扩展方法有什么特征:
第一个参数为扩展方法,我已经在前一篇文章《Linq快速入门——扩展方法》里提到了,我不做具体解释了,简单来说创建扩展方法就是这四步:
对于第二个参数:System.Func<TSource, bool> predicate),我们再来深究下。
所以再对上面的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);
}
Console.ReadKey();
}
//Func<int,bool>: 封装了一个具有一个int参数并且返回类型为bool类型的方法
static List<int> MyFilter(int[] array,Func<int,bool> filter)
{
List<int> list = new List<int>();
for (int i = 0; i < array.Length; i++)
{
if (filter(i))
{
list.Add(i);
}
}
return list;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LambdaDemo
{
class Program
{
static void Main(string[] args)
{
string[] names = {"Eyes","Voodoo","Tod","Chris","Christina","Maxisim" };
Func<string, bool> filter = s => s.Length > 5;
Func<string, string> order = s => s;
Func<string, string> operating = s => s.ToUpper();
IEnumerable<string> expr = names.Where(filter).OrderByDescending(order).Select(operating);
expr.ToList<string>().ForEach(i => Console.WriteLine(i));
Console.ReadKey();
}
}
}
例如将表达式(Price-5)*Count*Rebate表示成一棵二叉树可以用以下方式表达:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Lambda表达式树
{
class Program
{
static void Main(string[] args)
{
//计算(Price-5)*Count*Rebate
ParameterExpression paraPrice = Expression.Parameter(typeof(decimal),"price");
ConstantExpression constant = Expression.Constant(5m,typeof(decimal));
BinaryExpression result1 = Expression.Subtract(paraPrice, constant);
ParameterExpression paraCount = Expression.Parameter(typeof(decimal),"count");
ParameterExpression paraRebate = Expression.Parameter(typeof(decimal),"rebate");
BinaryExpression result2 = Expression.Multiply(paraCount,paraRebate);
BinaryExpression result3 = Expression.Multiply(result1,result2);
Expression<Func<decimal, decimal, decimal, decimal>> totalPrice = Expression.Lambda<Func<decimal, decimal, decimal, decimal>>(result3,paraPrice,paraCount,paraRebate);
Func<decimal, decimal, decimal, decimal> myFun = totalPrice.Compile();
Console.WriteLine(myFun(125m,10m,0.5m));
Console.ReadKey();
}
}
}
Expression<TDelegate> 类型提供 Compile 方法,该方法将表达式树表示的代码编译成一个可执行委托。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Expression<Func<int, int>> f1 = x => x + 1;
//f1(1)//...错误,必须将表达式树表示的代码编译成一个可执行委托
Func<int, int> f2 = f1.Compile();
Console.WriteLine(f2(2));
Console.ReadKey();
}
}
}
未完,持续更新中