lambda表达式

使用lambda表达式的一个场合是把lambda表达式赋予委托类型:在线实现代码。只要有委托参数类型的地方,就可以利用lambda表达式。前面使用匿名方法的例子可以改为使用lambda表达式。

using System;

namespace lambda
{
    class Program
    {
        static void Main(string[] args)
        {
            string mid = ", middle part";
            Func<string,string> lambda = param =>{
                param += mid;
                param += " and this was added to the string";
                return param;

            };
            string result = "Hello";
            Console.WriteLine("Start of string");
            System.Console.WriteLine($"{lambda(result)}");

        }
    }
}

lambda运算符“=>”的左边列出了需要的参数,而其右边定义了赋予labmda变量的方法的实现代码。

参数

lambda表达式有几种定义参数的形式。如果只有一个参数,只写出参数名就足够了。下面的lambda表达式使用了参数s。因为委托类型定义了一个string参数。实现代码调用方法返回一个字符串,在调用该委托时,就把字符串最终写入控制台。

Func<string,string> oneParam = s =>$"change uppercase {s.ToUpper()}";
System.Console.WriteLine(oneParam("test"));

如果委托使用多个参数就把这些参数名放在圆括号中。这里参数x和y的类型是double,由Func<double,double>委托定义:

Func<double,double,double> twoParam = (x,y) => x*y;
System.Console.WriteLine(twoParam(3,2));

为了方便起见,可以在圆括号中给变量名添加参数类型。如果编译器不能匹配重载后的版本,那么使用参数类型可以帮助找到匹配的委托。

Func<double,double,double> twoParamWithTypes = (double x,double y)=>x*y;
System.Console.WriteLine(twoParamWithTypes(4,2));

多行代码

如果lambda表达式只有一条语句,在方法块内就不需花括号和return语句,因为编译器会添加一条隐式的return语句:

Func<double,double> squre = x =>x*x;

添加花括号、return语句和分号是完全合法的,通常这比不添加这些符号更容易阅读:

Func<double,double> squre = x =>
{
  return x*x;
};

但是,如果在lambda表达式的实现代码中需要多条语句,就必须添加花括号和return语句:

            string mid = ", middle part";
            Func<string,string> lambda = param =>{
                param += mid;
                param += " and this was added to the string";
                return param;

            };

闭包

通过lambda表达式可以访问lambda表达式块外部的变量,这称为闭包。闭包是非常好用的功能,但如果使用不当也会非常的危险。

在下面的示例中,Func<int,int>类型的lambda表达式需要一个int参数,返回一个int值。该lambda表达式的参数用变量x定义。实现代码还访问了lambda表达式外部的someVal。只要不假设在调用f时,lambda表达式创建了一个以后使用的新方法,这似乎没有什么问题。看看下面的代码块,调用f的返回值应是x加5的结果,但实情似乎不是这样:

int someVal = 5;
Func<int,int> f = x=>x+someVal;

假定以后要修改变量someVal,于是调用lambda表达式时,会使用someVal的新值。调用f(3)的结果是10:

someVal = 7;           
System.Console.WriteLine(f(3));

同样,在lambda表达式中修改闭包的值,可以在lambda表达式的外部访问已改动的值。

现在我们也许会奇怪,如何在lambda表达式的内部访问lambda表达式外部的变量。为了理解这一点,看看编译器在定义lambda表达式时做了什么。对于lambda表达式x=>x+someVal,编译器会创建一个匿名类,它有一个构造函数来传递外部变量。该构造函数取决于从外部访问变量数。对于这个简单的例子,构造函数接受一个int值。匿名类包含一个匿名方法,其实现代码、参数和返回类型由lambda表达式定义:

        public class AnonymousClass{
        private int someVal;
        public AnonymousClass(int someVal){
            this.someVal = someVal;
        }
        public int AnonymousMethod(int x) => x+someVal;
    }

使用lambda表达式并调用该方法,会创建匿名类的一个实例,并传递调用该方法时变量的值。

注:

如果给多个线程使用闭包,就可能遇到并发冲突。最好仅给闭包使用不变的类型。这样可以确保不改变值,也不需要同步

lambda表达式可以用于类型为委托的任意地方。类型是Expression或Expression<t>时,也可以使用lambda表达式,此时编译器会创建一个表达式树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值