现在的位置: 首页 > 综合 > 正文

Lambda表达式–NET4

2013年02月13日 ⁄ 综合 ⁄ 共 4466字 ⁄ 字号 评论关闭

什么是Lambda表达式

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

简单使用

所有 Lambda
表达式都使用 Lambda
运算符 =>,该运算符读为“goes to” Lambda 运算符的左边是输入参数(如果有),右边包含表达式或语句块。 Lambda 表达式 x => x * x 读作“x goes
to x times x”
。可以将此表达式分配给委托类型,如下所示:

创建委托

delegate int del(int i);

static void Main(string[] args)

{

   
del myDelegate = x => x * x;

   
int j = myDelegate(5); //j = 25

}

 

表达式树类型

using System.Linq.Expressions;

 

namespace ConsoleApplication1

{

   
class Program

    {

       
static void Main(string[] args)

       
{

           
Expression<del> myET = x => x * x;

       
}

    }

}

 

Lambda 中的类型推理

 

在编写 Lambda 时,通常不必为输入参数指定类型,因为编译器可以根据 Lambda 主体、基础委托类型以及 C# 语言规范中描述的其他因素推断类型。对于大多数标准查询运算符,第一个输入是源序列中的元素的类型。因此,如果要查询 IEnumerable<Customer>,则输入变量将被推断为 Customer 对象,这意味着您可以访问其方法和属性:

customers.Where(c => c.City ==
"London");

Lambda 的一般规则如下:

·        
Lambda 包含的参数数量必须与委托类型包含的参数数量相同。

·        
Lambda 中的每个输入参数必须都能够隐式转换为其对应的委托参数。

·        
Lambda 的返回值(如果有)必须能够隐式转换为委托的返回类型。

 

注意事项

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

2 Lambda 在基于方法的 LINQ 查询中用作标准查询运算符方法(如 Where)的参数。

使用基于方法的语法在 Enumerable 类中调用 Where 方法时(像在 LINQ to Objects LINQ to XML 中那样),参数是委托类型 System.Func<T,
TResult>
使用 Lambda 表达式创建委托最为方便。 例如,当您在 System.Linq.Queryable 类中调用相同的方法时(像在 LINQ to SQL 中那样),则参数类型是 System.Linq.Expressions.Expression<Func>,其中 Func 是包含至多十六个输入参数的任何 Func 委托。 同样,Lambda 表达式只是一种用于构造表达式树的非常简练的方式。 尽管事实上通过 Lambda 创建的对象的类型是不同的,但 Lambda 使得 Where 调用看起来类似。

在前面的示例中,请注意委托签名具有一个 int 类型的隐式类型输入参数,并返回 int 可以将 Lambda 表达式转换为该类型的委托,因为该表达式也具有一个输入参数 (x),以及一个编译器可隐式转换为 int 类型的返回值。 (以下几节中将对类型推理进行详细讨论。) 使用输入参数 5 调用委托时,它将返回结果 25

3 is as 运算符的左侧不允许使用 Lambda

 

Lambda 表达式

表达式在右边的 Lambda
表达式称为“Lambda
表达式Lambda 表达式在构造表达式树(C# Visual Basic时广泛使用。Lambda 表达式返回表达式的结果,并采用以下基本形式:

 (input parameters) =>
expression

只有在 Lambda
有一个输入参数时,括号才是可选的;否则括号是必需的。两个或更多输入参数由括在括号中的逗号分隔:

 (x, y) => x == y

有时,编译器难于或无法推断输入类型。如果出现这种情况,您可以按以下示例中所示方式显式指定类型:

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

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

 () => SomeMethod()

 

delegate int DelegateMultiply(int
x, int y);

 

        /// <summary>

        /// Lambda表达式乘法

        /// </summary>

        /// <param
name="x"></param>

        /// <param
name="y"></param>

        /// <returns></returns>

        public static int Multiply(int x, int y)

        {

            DelegateMultiply
del = (m, n) => m * n;

 

            return
del(x, y);

        }

 

 

 

Lambda 语句

Lambda 语句与 Lambda 表达式类似,只是语句括在大括号中:

像匿名方法一样,Lambda 语句无法用于创建表达式树。== 匿名方法

 

(input
parameters) => {statement;}

 

        /// <summary>

        /// Lambda语句乘法

        /// </summary>

        /// <param
name="x"></param>

        /// <param
name="y"></param>

        /// <returns></returns>

        public static int
MultiplyStatement(int x, int y)

        {

            DelegateMultiply
del = (m, n) => { return m * n; };

 

            return
del(x, y);

        }

 

带有标准查询运算符的 Lambda

1 许多标准查询运算符都具有输入参数,其类型是泛型委托 Func<T,
TResult>
系列的其中之一。Func<T,
TResult>
委托使用类型参数定义输入参数的数目和类型,以及委托的返回类型。Func 委托对于封装应用于一组源数据中每个元素的用户定义表达式非常有用。例如,假设有以下委托类型:

 Func<int, bool> myFunc = x => x
== 5;

bool
result = myFunc(4); // returns false of course

2当参数类型为 Expression<Func> 时,您也可以提供 Lambda 表达式,例如在 System.Linq.Queryable 内定义的标准查询运算符中。如果指定 Expression<Func> 参数,Lambda 将编译为表达式树。

   int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2,
0 };

int
oddNumbers = numbers.Count(n => n % 2 == 1);

 

Lambda 表达式中的变量范围

Lambda 可以引用外部变量,这些变量的范围是位于定义 Lambda 的封闭方法或类型里面。

并且即使这些””””外部变量超出了范围或者已经被回收,但是这些变量仍然保存着,Lambda 再次使用.

 

 

1 必须明确地分配外部变量,然后才能在 Lambda 表达式中使用该变量。

lambda中引用的变量 ,在委托有效的范围内均有效.

2
 Lambda
表达式里面声明的变量,外部方法或者类无法访问.


3  Lambda
表达式无法从封闭方法中直接捕获 ref out 参数。
private void Scope( out int input)

{

      Lambda{ 不能拿 input}

}


4  lambda
表达式中有return 只是跳出lambda ,然后继续执行方法中 lambda下面的语句,不会跳出lambda所在的方法。

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

continue

 

1 举一个例子:

 

        

       // Lambda 表达式中的变量范围 测试

       public  delegate bool D1();

       public  delegate bool D2(int i);

       private D2 d2;

 

        /// <summary>

        /// Lambda 表达式中的变量范围 测试

        /// </summary>

        /// <param
name="input"></param>

        private  void Scope(int input)

        {

            int
j = 0;

 

 

            // 这里 j input 是外部变量--对于Lambda表达式而言.

             D1  dl = () => { j = 10; return j > input; };

 

            // d2 将在 本方法外被触发,用以证明 j 在外部仍被保留.

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

           

            //
Output: j = 0

            // 因为委托还未被触发.

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

 

            // 触发委托

            bool
boolResult = dl();

 

            // 此时: j = 10 b = True

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

        }

 

  -----测试

         /// <summary>

        /// Lambda 表达式中的变量范围 测试

        /// </summary>

        public  void
ScopeTest()

        {

            this.Scope(5);

 

            // 触发d2,

            bool
result = d2(10);

            //
Output: True;
说明d2能拿到j的副本.尽管j已经结束了生命周期0.

            //证明此时外部仍有Scope()中变量j的副本,尽管 Scope() 执行结束,j值为10.

         // 所以: lambda中引用的变量 ,在委托(D2委托是在类中均可访问)有效的范围内均有效.

            Console.WriteLine(result);

 

            Console.ReadKey();

 

        }

 

参考:

http://msdn.microsoft.com/zh-cn/library/bb397687.aspx

抱歉!评论已关闭.