• Linq学习总结(4)——Lambda表达式


    Lambda表达式的演化

    要了解Lambda表达式,我们首先应从委托说起。.NET中的委托实际上就是C语言中的函数指针,函数通过地址进行引用,只不过.NET中它更加好看了而已。

    delegate void FunctionPoint(string str);

    static void printHello(string name)
    {
    Console.WriteLine(
    "Hello {0}", name);
    }

    static void Main(string[] args)
    {
    FunctionPoint fp
    = printHello;
    fp(
    "heqichang");
    }
    /*Ouput
    * Hello heqichang
    */

    然后,委托在.NET2.0中又被精简成了匿名委托

    delegate void FunctionPoint(string str);

    static void Main(string[] args)
    {
    FunctionPoint fp
    = delegate(string name)
    {
    Console.WriteLine(
    "Hello {0}",name);
    };
    fp(
    "heqichang");
    }
    /*Ouput
    * Hello heqichang
    */

    匿名委托省略了函数名、返回类型以及参数类型,变得更加轻量

    delegate void FunctionPoint(string str);

    static void Main(string[] args)
    {
    FunctionPoint fp
    = s => Console.WriteLine("Hello {0}",s);
    fp(
    "heqichang");
    }
    /*Ouput
    * Hello heqichang
    */

    现在我们看到的表达式就是通过委托一步一步简化而来的。我们的Lambda表达式就是一个简洁的委托。左侧(相对于=>)代表函数的参数,右侧就是函数体。

    在System命名空间中,微软已经为我们预定义了几个泛型委托Action、Func、Predicate。Action用于在泛型参数上执行一个操作;Func用于在参数上执行一个操作并返回一个值;Predicate<T>用于定义一组条件并确定参数是否符合这些条件。

     

    表达式树

    Lambda表达式还有个重要的用途就是用来构建表达式树:

    static void Main(string[] args)
    {
    Expression
    <Func<int, int, int>> exp = (a, b) => a * (b + 2);

    ParameterExpression param1
    = (ParameterExpression)exp.Parameters[0];
    ParameterExpression param2
    = (ParameterExpression)exp.Parameters[1];
    BinaryExpression operation
    = (BinaryExpression)exp.Body;
    ParameterExpression left
    = (ParameterExpression)operation.Left;
    BinaryExpression operation2
    = (BinaryExpression)operation.Right;
    ParameterExpression left2
    = (ParameterExpression)operation2.Left;
    ConstantExpression right2
    = (ConstantExpression)operation2.Right;

    Console.WriteLine(
    "Decomposed expression: ({0},{1}) => {2} {3} ({4} {5} {6})",
    param1.Name, param2.Name, left.Name, operation.NodeType, left2.Name,
    operation2.NodeType, right2.Value);

    Func
    <int, int, int> func = exp.Compile();
    Console.WriteLine(func(
    2,2));
    /*Ouput
    * 8
    */
    }

    我们上面的lambda表达式构建了这么一个表达式树:

    闭包

    如果将一个变量声明在一个函数内部,该变量就只会在该函数的栈内存中。当函数返回,这个本地变量也同时从栈内存中被清除了。当你在Lambda表达式中使用本地变量时,该变量就会在函数的栈空间清理时被移除。为了防止这样的事发生,当一个依赖于本地变量的Lambda表达式需要从函数中返回时,编译器就会创建一个闭包(Closure,也就是一个包装器类)。

    static void Main(string[] args)
    {
    int x = 1;
    Func
    <int, int> add = y => x + y;
    Console.WriteLine(add(
    3));
    /*Output
    * 4
    */
    }

    我们通过ILDasm可以看到,编译器帮我们自动创建了一个类,用于保存本地变量,以扩展它们的生命周期

  • 相关阅读:
    VS2017试用期到期后登录微软账户出现错误解决方法
    Unable to start process "dotnet-projectmodel-server" while starting VS2015 问题
    如何写.gitignore只包含指定的文件扩展名
    Win7 通过Smb共享CentOS文件步骤
    Linux下用sudo 命令时出现 is not in the sudoers file
    ubuntu下安装chorme浏览器
    qt for ios扫描二维码功能实现
    ubuntu14.04登陆后只显示桌面文件,快速启动栏不显示,终端不能打开
    编译 Qt with Openssl for IOS
    sql print原理
  • 原文地址:https://www.cnblogs.com/heqichang/p/2092217.html
Copyright © 2020-2023  润新知