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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM