zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    ViewFlow增强onItemClick功能及ViewFlow AbsListView源代码分析
    函数递归与迭代
    UIPanGestureRecognizer上下左右滑动方向推断算法
    Eclipse中的Web项目自己主动部署到Tomcat
    《从程序猿到项目经理》读后感-职业瓶颈
    安卓开发之简单的短信操作模块
    [Swift通天遁地]二、表格表单-(15)自定义表单文本框内容的格式
    [Swift通天遁地]二、表格表单-(14)实时调整表单元素的激活和失效
    [Swift通天遁地]二、表格表单-(13)实时调整表单元素的显示和隐藏
    [Swift通天遁地]二、表格表单-(12)设置表单文字对齐方式以及自适应高度的文本区域TextArea
  • 原文地址:https://www.cnblogs.com/wardensky/p/5938860.html
Copyright © 2011-2022 走看看