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 

参考

IT虾米网
IT虾米网
IT虾米网

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/20948.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论