Lambda表达式
前言
Lambda表达式跟Linq关系不大,不是一回事!
举例说明:
var _Results = from item in _List
where item.Value == 1
select item;
这是一个Linq
var _Results = _List.Where(x => x.Value == 1);
上面这个也是一个Linq,不过他用了Lambda表达式。
学习Lambda表达式的过程应该是这样的。
st=>start: start
op1=>operation: 委托
op2=>operation: 匿名方法
op3=>operation: Lambda表达式
e=>end
st->op1->op2->op3->e
委托
略。
匿名方法
button1.Click += delegate(System.Object o, System.EventArgs e)
{MessageBox.Show("Click!"); };
或者
// Create a delegate.
delegate void Del(int x);
// Instantiate the delegate using an anonymous method.
Del d = delegate(int k) { /* ... */ };
Lambda表达式
常见Lambda
上面那个匿名方法可以写成如下的样子。
button2.Click += (System.Object o, System.EventArgs e1) => MessageBox.Show("哈哈");
这就是Lambda表达式。
多线程Lambda的例子
常见的多线程这么写。
public void MultiThreadTest()
{
Thread t = new Thread(new ThreadStart(this.SingleThread));
t.Start();
}
public void SingleThread()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
Thread.Sleep(1000);
}
}
改成Lambda表达式的样子。
public void LambdaThreadTest()
{
Thread t = new Thread(() =>
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
Thread.Sleep(1000);
}
});
t.Start();
}
说说LambdaExpression
先看看下面这段代码
Func<int, bool> myFunc = (i) => i == 5;
这段代码定义了一个委托,返回值是bool。这个委托也恰好是where子句的参数。
用法如下:
Func<int, bool> myFunc = (i) => i < 5;
List<int> myList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };
var newList = myList.Where(myFunc);
where方法的语法如下:
//
// 摘要:
// 基于谓词筛选值序列。
//
// 参数:
// source:
// 要筛选的 System.Collections.Generic.IEnumerable<T>。
//
// predicate:
// 用于测试每个元素是否满足条件的函数。
//
// 类型参数:
// TSource:
// source 中的元素的类型。
//
// 返回结果:
// 一个 System.Collections.Generic.IEnumerable<T>,包含输入序列中满足条件的元素。
//
// 异常:
// System.ArgumentNullException:
// source 或 predicate 为 null。
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
明白了上面的代码,下面说一下Expression,上面的代码还有下面这种写法。
Expression<Func<int, bool>> myFunc = (i) => i < 5;
List<int> myList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };
var newList = myList.AsQueryable().Where(myFunc);
先说把Expression怎么变成Func<int, bool>
Func<int, bool> myFunc = myExpr1.Compile();
这种写法把委托变成了Expression,这有什么好处呢?
如果我要表达小于5的同时要大于2,怎么办呢?
List<int> myList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };
Expression<Func<int, bool>> myExpr1 = (i) => i < 5;
Expression<Func<int, bool>> myExpr2 = (i) => i > 2;
var invokedExpr = Expression.Invoke(myExpr2, myExpr1.Parameters.Cast<Expression>());
Expression<Func<int, bool>> myExpr3 = Expression.Lambda<Func<int, bool>>(Expression.And(myExpr1.Body, invokedExpr), myExpr1.Parameters);
var newList = myList.AsQueryable().Where(myExpr3);
上述代码能实现两个Expression的And运算。
具体实现And和Or运算的代码如下:
using System;
using System.Linq;
using System.Linq.Expressions;
namespace InternationalReport
{
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.Or(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.And(expr1.Body, invokedExpr), expr1.Parameters);
}
}
}
应用这段代码之后,原来代码改为:
List<int> myList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };
Expression<Func<int, bool>> myExpr1 = (i) => i < 5;
Expression<Func<int, bool>> myExpr2 = (i) => i > 2;
Expression<Func<int, bool>> myExpr3 = myExpr1.And(myExpr2);
Console.WriteLine(myExpr3.ToString());
var newList = myList.Where(myExpr3.Compile());
Console.WriteLine(newList.Count());
输出
i => ((i < 5) And Invoke(i => (i > 2), i))
说说Lambda表达式树
博客园上有位老兄把Lambda表达式树说的很明白,见参考。
我从MSDN拿了一段代码,示例代码如下:
List<int> myList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numParam });
var newList = myList.Where(lambda1.Compile());
Console.WriteLine(newList.Count());
这段代码跟上面的意思是一样的。
那为什么要把那么简单的代码写的这么复杂呢?其实Expression Trees还可以写的更复杂,下面还是MSDN上的一个例子
// Creating a parameter expression.
ParameterExpression value = Expression.Parameter(typeof(int), "value");
// Creating an expression to hold a local variable.
ParameterExpression result = Expression.Parameter(typeof(int), "result");
// Creating a label to jump to from a loop.
LabelTarget label = Expression.Label(typeof(int));
// Creating a method body.
BlockExpression block = Expression.Block(
// Adding a local variable.
new[] { result },
// Assigning a constant to a local variable: result = 1
Expression.Assign(result, Expression.Constant(1)),
// Adding a loop.
Expression.Loop(
// Adding a conditional block into the loop.
Expression.IfThenElse(
// Condition: value > 1
Expression.GreaterThan(value, Expression.Constant(1)),
// If true: result *= value --
Expression.MultiplyAssign(result,
Expression.PostDecrementAssign(value)),
// If false, exit the loop and go to the label.
Expression.Break(label, result)
),
// Label to jump to.
label
)
);
// Compile and execute an expression tree.
int factorial = Expression.Lambda<Func<int, int>>(block, value).Compile()(3);
Console.WriteLine(factorial);
还可以看一下表达式树是咋回事。
// Create an expression tree.
Expression<Func<int, bool>> exprTree = num => num < 5;
// Decompose the expression tree.
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
// This code produces the following output:
// Decomposed expression: num => num LessThan 5
参考
http://www.cnblogs.com/tianguook/p/3950059.html
http://www.cnblogs.com/knowledgesea/p/3163725.html
https://msdn.microsoft.com/en-us/library/mt654263.aspx