C#——lambda表达式

>>lambda表达式就是用来代替委托实例的未命名方法。

编译器会把lambda表达式转化为以下二者之一:

1. 一个委托实例;

2. 一个表达式树(expression tree),类型是Expression<TDelegate>,它表示了可遍历的对象模型中lambda表达式的代码;它允许lambda表达式延迟到运行时再被解释。

delegate int Transformer(int i);
Transformer sqr = x=>x*x;
Console.WriteLine(sqr(3));

//编译器会通过编写一个私有方法来解析这个lambda表达式,然后把表达式的代码移动到这个方法里

 

>>lambda表达式的形式

(parameter)=> expression or statement-block

如果只有一个参数并且参数类型是可推断的话,那么参数的小括号可以省略。

 

 

>>lambda表达式与Action和Func

lambda表达式通常与Action和Func一起使用

Func<int, int> sqr = x=>x*x;

Func<int, int> getLen = (str1, str2)=>str1.length()+str1.length();
int totalLen = getLen("hello", "world");

 

>>显示声明参数类型

void Foo<T>(T t){//...}
void Bar<T>(Action<T> a){//...}

void main()
{
    Bar(x => Foo(x));    //无法通过编译
    Bar((int x) => Foo(x));    //申明类型
    Bar<int>(x => Foo(x));
    Bar<int>(Foo);    //methods group
}

 

 

 

>>捕获外部变量

lambda表达式可以引用本地的变量和所在方法的参数。

被引用的外部变量叫做被捕获的变量(captured variable);

捕获了外部变量的lambda表达式称为闭包;

被捕获的变量实在实际被调用的时候才会被计算,而不是被捕获的时候;

int factor = 2;
Func<int, int> multiplier = x=>x*factor;

factor = 10;
Console.WriteLine(multiplier(3));    //30

lambda表达式本身也可以更新被捕获的对象;

int seed=0;
Func<int> natural = () => seed++;

Console.WriteLine(natural());    //0
Console.WriteLine(natural());    //1
Console.WriteLine(seed);    //2

被捕获变量的生命周期会被延长到和委托一样;

static Func<int> Natural()
{
    int seed =0;
    return ()=>seed++;
}


void main()
{
    Func<int> natural = Natural();
    Console.WriteLine(natural());    //0
    Console.WriteLine(natural());    //1

}

lambda表达式里面,实例化的变量对于委托实例的每次调用来说都是唯一的;

static Func<int> Natural()
{
    
    return ()=>{int seed =0; return seed++;}
}


void main()
{
    Func<int> natural = Natural();
    Console.WriteLine(natural());    //0
    Console.WriteLine(natural());    //0

}

 

 

 

捕获迭代变量

捕获迭代变量时,C#会把这个变量当作循环的外部定义的变量,这意味着每次捕获的都是同一个值;

Action[] actions = new Action[];

for(int i=0;i<3;i++)
{
    actions[i] = () => WriteLine(i);
}

foreach(a in actions)
{
    a();    //333
}

//相当于如下的写法
Action[] actions = new Action[];

int i = 0;
actions[1] = () => WriteLine(i);
i = 1;
actions[1] = () => WriteLine(i);
i = 2;
actions[1] = () => WriteLine(i);
i = 3;

foreach(a in actions)
{
    a();    //333
}


//解决方法
Action[] actions = new Action[];

for(int i=0;i<3;i++)
{
    int loopInt = i;    //因为此处的变量在每个loop中保存在不同的内存地址
    actions[i] = () => WriteLine(loopInt);
}

foreach(a in actions)
{
    a();    //012
}

 

 

lambda表达式与本地方法

 

 

匿名方法 vs lambda表达式

匿名方法和lambda表达式很像,但是:

1. 不能使用隐式类型参数;

2. 不能使用表达式语法,必须使用语法块;

3. 没有编译表达树的能力,不能赋值给Expression<I>;

 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页