在我年少的时候 身边的人说不可以流泪
宅男—coding 篮球 旅行 上网 睡觉......

MSDN 定义:"Lambda 表达式" 是一个匿名函数,它可以包含表达式和语句, 并且可用于创建委托或表达式树类型.

匿名方法是在2.0中引入,在之后的3.0 及 更高版本中, Lambda表达式取代了匿名方法,作为编写内联代码的首选方式. 因为在之前项目中一直没用,也没去了解, 所以现在整理一下, 赶紧补上这一课.

首先, 回顾一下匿名函数: 

要将代码块传递为委托参数,那么唯一的方法就是创建匿名函数, Example

 

delegate void Fun(string str);

Fun f
= delegate(string str){
Console.WriteLine(str);
};
f(
"hello world");

通过使用匿名方法, 因为不必创建单独的方法, 所以减少了实例化委托所需的系统开销.

线程也是一个很好的例子:

 

System.Threading.Thread thd = new System.Threading.Thread
(
delegate()
{
Console.WriteLine(
"first");
}
);
thd.Start();

OK 现在回到"Lambda 表达式"

所有Lambda 表达式都使用 =>, 该运算符读为"goes to", 运算符左边是输入参数(如果有), 右边包含表达式或者代码语句块. x=>x * x 读作:"x goes to x times x"

=>运算符与赋值(=)有相同的优先级,并且是右结合运算符.

 

1、Lambda 表达式

表达式在右边的 Lambda表达式称为"Lambda 表达式' (input parameters)=> expression

当只有一个参数时,左边输入参数括号才是可选的, 两个或更多输入参数, 则必须有括号, 参数用逗号分隔 

(x,y)=> x==y

有时,编译器无法推断输入类型, 你可以显式指定参数类型:

 

(int x, string s) => s.Length > x

使用空括号指定零个输入参数:

() => SomeMethod()

2、Lambda 语句

Lambda 语句与 Lambda 表达式类似, 把执行语句块放到大括号中 (input parameters) => {statement;}

Lambda 语句块可以包含任意数量语句, 但是实际项目中尽量以少为宜, 这样读起来比较清晰,一般也就三个语句.

 

delegate void Fun(string str1,string str2);
Fun f
= (n, m) => { Console.WriteLine(n + m + "World"); };
f(
"Hello", "Our");

3、带有标准查询运算符的Lambda

 

许多标准查询运算符都具有输入参数, 其类型是泛型委托Func<T,TResult>系列之一. Lambda 表达式的基础类型是泛型 Func 委托之一.

Func<T,TResult>委托:封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。

 

public delegate TResult Func<in T, out TResult>(
T arg
)

下面就实例化一个Func<int,bool> 委托, int 是输入参数,bool 是返回值.Example

 

Func<int, bool> myFun = x => x == 7; or Func<int, bool> myFun = (int x) => x == 7;
bool b = myFun(5); // false

下面显示一个标准查询运算符:

int[] numbers = { 3, 4, 5, 6, 7 };
int SumNumbers = numbers.Count(n => n % 2 == 1); //3

这里Count方法

public static int Count<TSource>(
this IEnumerable<TSource> source,
Func
<TSource, bool> predicate
)
其中source 包含测试和计数的元素的序列. predicate 测试每个元素是否满足条件的函数

4、Lambda 中的类型推断

在编写Lambda时,通常不必为输入参数指定类型, 编译器可以根据Lambda 主体、基础委托类型和C#语言规范描述的其他因素推断类型.

而大多数标准查询运算符,第一个输入是源序列中的元素类型.

customers.Where(c => c.City == "ShangHai"); //这里的输入参数 c 就被推断为customers 对象 

Lambda的一般规则:

  • Lambda包含的参数数量必须与委托类型包含的参数数量一致
  • Lambda中每个输入参数必须能隐式转换成其对应的委托参数
  • Lambda返回值必须能够隐式转换成委托的返回类型
  • 

5、Lambda表达式中的变量范围

先看一段代码

delegate bool del();
delegate bool del2(int i);

class Program
{
del del;
del2 del2;
static void Main(string[] args)
{
Program test
= new Program();
test.TestMethod(
5);

bool result = test.del2(10);

Console.WriteLine(result);

Console.Read();
}

public void TestMethod(int input)
{
int j = 0;

del
= () => { j = 10; return j > input; };

del2
= (x) => { return x == j; };

Console.WriteLine(
"j = {0}", j);

bool boolResult = del();

Console.WriteLine(
"j = {0}.b = {1}", j, boolResult);
}
}

看看输出结果

MSDN解释:Lambda 可以引用“外部变量”,这些变量位于在其中定义 Lambda 的封闭方法或类型的范围内。 将会存储通过这种方法捕获的变量以供在 Lambda 表达式中使用,即使变量将以其他方式超出范围或被作为垃圾回收。 必须明确地分配外部变量,然后才能在 Lambda 表达式中使用该变量。

看起来比较难理解一点, 具体针对下面规则做一些解释,有理解错误的地方还请各位大侠指出 J

  

1)捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。

      Lambda所使用的变量,在委托的生命周期内不会被垃圾回收. 要让委托承载的方法数超出范围估计很难达到,

     这个具体委托能承载多少个方法,我也想知道, 我试了加载100W个方法,也没出现问题, 这个应该和内存有关, 只要你机器有足够的内存.

 

2)在外部方法中看不到 Lambda 表达式内引入的变量。

delegate bool D();
D del;
for (int a = 0; a < 4; a++)
{
del
+= () => { int t = 0; return true; };
Console.WriteLine(
"t={0}", t); //这里无法访问Lambda中定义的变量t
}

  

3)Lambda 表达式无法从封闭方法中直接捕获 ref  out 参数。

delegate string Fun(string str);

public void TestMethod(string str1, ref string str2)
{
Fun f
= x => { return x + str1 + " world"; }; //这里如果把str1换成str2就会出错
}
//上面第二条外部方法无法访问Lambda表达式内的变量, 但反过来是可以的, 就像这个例子中Lambda访问外部的变量str1

    如果委托中有ref或out参数,则Lambda必须有参数类型(即显示类型)     

 

delegate bool D2(int i,ref string str);
D2 del2;
for (int a = 0; a < 4; a++)
{
del2
+= (int x, ref string c) =>
{ c
= c + "j"; Console.WriteLine(x + c); return true; };//这里必须显示参数类型 x, c}
string s="sadf";
del2(
5,ref s);
Console.WriteLine(s);
 

 

 4)Lambda 表达式中的返回语句不会导致封闭方法返回。

    Lambda表达式中return 只是跳出Lambda, 然后继续执行方法中Lambda下面的语句, 不会跳出当前所在的方法.

  

5)Lambda 表达式不能包含其目标位于所包含匿名函数主体外部或内部的 goto 语句、break 语句或 continue 语句。   

del += () => { int t = 0; break; return true; };
//这里会出现如下语法错误 Control cannot leave the body of an anonymous method or lambda expression 
posted on 2011-01-25 23:28  JACKALMA  阅读(1143)  评论(4编辑  收藏  举报