lambda表达式

1、什么是lambda表达式

    lambda表达式实际上是匿名方法的变形。
    在C#2.0中引入了匿名方法,允许在期望出现委托的时候以“内联”的代码替代之。尽管匿名方法提供了函数式编程语言中的很多表达能力,但匿名方法的语法实在是太罗嗦了,并且很不自然。Lambda表达式为书写匿名方法提供了一种更加简单、更加函数化的语法。
    实际上lambda表达式本质上就是匿名方法,当我们在编译代码程序的时候编译器会自动地将lambda表达式转换成匿名方法。
 
2、lambda表示式的创建
    lambda表达式的运算符为“=>”,读做“goesto”。左边为参数列表,右边为语句或语句块。如下:
    参数列表=>语句或语句块
    x=>x*x;
    (x,y)=>x+y;

    参数列中可包含任意个参数(与委托对应),如果参数列中有0个或1个以上参数,则必须使用括号括住参数列,如下:

() => Console.Write("0个参数");

i => Console.Write("1个参数时参数列中可省略括号,值为:{0}", i);

(x, y) => Console.Write("包含2个参数,值为:{0}:{1}", x, y);

    而“语句或语句块”中如果只有一条语句,则可以不用大括号括住,否则则必须使用大括号,如下所示:

i => Console.Write("只有一条语句");

i => { Console.Write("使用大括号的表达式"); };

//两条语句时必须要大括号

i => { i++; Console.Write("两条语句的情况"); };

 

3、实例说明

    我还是继续用“委托”文章中排序的那个例子讲,这次贴出完整代码。
    先新建Student类:
    public class Student {
        //这里为了简便就不用属性了
        public int id;
        public string name;
        public int age;
        public int classId;//假设有一个班级编号
        public Student(int id, string name, int age, int classId)
        {
            this.id = id;
            this.name = name;
            this.age = age;
            this.classId = classId;
        }
    }

    新建一个aspx的页面,拖入控件button和Label:

    <asp:Button ID="Button2" runat="server" Text="lambda表达式的运用" onclick="Button2_Click" />
    <br />
    <asp:Label ID="Label2" runat="server" Text=""></asp:Label>

    在页面的cs文件中添加排序的方法(定义委托):

        //使用委托,当然这种可以用泛型来解决
        public delegate bool CompareDelegate(Student s1, Student s12);
        private void Sort(Student[] s,CompareDelegate method)
        {
            for (int i = 0; i < s.Length - 1; i++)//控制轮数
            {
                for (int j = 0; j < s.Length - 1 - i; j++)//控制交换次数
                {
                    if (method(s[j],s[j+1]))//根据age排名
                    {
                        Student temp = s[j];
                        s[j] = s[j + 1];
                        s[j + 1] = temp;
                    }
                }
            }
        }

    在button的响应函数中添加响应函数:

    //lambda表达是实现
    Sort(s,((Student s1,Student s2)=>s1.id > s2.id));
    //Sort(s, ((Student s1, Student s2) => s1.age > s2.age));

运行结果如下:

lambda表达式

在这里的lambda表达式实际上就是对匿名函数的一种简写,参照上篇博客“匿名函数和扩展函数”中的匿名函数的使用方法:
//匿名方法实现
Sort(s, delegate(Student s1, Student s2)
{
return s1.id > s2.id;
});
//Sort(s, delegate(Student s1, Student s2)
//{
//    return s1.age > s2.age;
//});
private bool CompareById(Student s1, Student s2)//具体实现
{
       return s1.id > s2.id;
}
private bool CompareByAge(Student s1, Student s2)
{
       return s1.age > s2.age;
}

 

4、lammda表达式使用范围
    由于Lambda表达式实际是匿名函数,它可以赋值到一个委托,而在IEnumerable<T>的方法中很多都通过函数委托来实现自定义的运算、条件等操作,所以Lambda表达式在Linq中被广泛使用。
 
5、lambda表达式遵循规则
    Lambda表达式是委托的实现方法,所以必须遵循以下规则:
        Lambda表达式的参数数量必须和委托的参数数量相同;
        如果委托的参数中包括有ref或out修饰符,则Lambda表达式的参数列中也必须包括有修饰符;
   class Test
    {
        delegate void OutHandler(out int x);
        static void Print(OutHandler test)
        {
            int i;
            test(out i);
            Console.Write(i);
        }
        static void Main()
        {
            Print((out int x) => x = 3);
            Console.Read();
        }
    }
        如果委托有返回类型,则Lambda表达式的语句或语句块中也必须返回相同类型的数据;
        如果委托有几种数据类型格式而在Lambda表达式中编译器无法推断具体数据类型时,则必须手动明确数据类型。

  C# 2.0规范中提到的匿名方法规范同样适用于Lambda表达式。Lambda表达式是匿名方法在功能行上的超集,提供了下列附加的功能:

    Lambda表达式允许省略参数类型并对其进行推断,而匿名方法要求参数类型必须显式地声明。

    Lambda表达式体可以是表达式或语句块,而匿名方法体只能是语句块。

    在类型参数推导和方法重载抉择时,Lambda表达式可以被作为参数传递。

    以一个表达式作为表达式体的Lambda表达式可以被转换为表达式树。

 
6、Lambda表达式转换

  和匿名方法表达式类似,Lambda表达式可以归类为一种拥有特定转换规则的值。这种值没有类型,但可以被隐式地转换为一个兼容的委托类型。特别地,当满足下列条件时,委托类型D兼容于Lambda表达式L:

  D和L具有相同数量的参数;

  如果L具有显式类型的参数列表,D中每个参数的类型和修饰符必须和L中相应的参数完全一致;

  如果L具有隐式类型的参数列表,则D中不能有ref或out参数;

  如果D具有void返回值类型,并且L的表达式体是一个表达式,若L的每个参数的类型与D的参数一致,则L的表达式体必须是一个可接受为statement-expression的有效表达式;

  如果D具有void返回值类型,并且L的表达式体是一个语句块,若L的每个参数的类型与D的参数一致,则L的表达式体必须是一个有效语句块,并且该语句块中不能有带有表达式的return语句;

  如果D的返回值类型不是void,并且L的表达式体是一个表达式,若L的每个参数的类型与D的参数一致,则L的表达式体必须是一个可以隐式转换为D的返回值类型的有效表达式;

  如果D的返回值类型不是void,并且L的表达式体是一个语句块,若L的每个参数的类型与D的参数一致,则L的表达式体必须是一个有效的语句块,该语句块不能有可达的终点(即必须有return语句),并且每个return语句中的表达式都必须能够隐式转换为D的返回值类型。

 
7、带有标准查询运算符的lambda

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

public delegate TResult Func<TArg0, TResult>(TArg0 arg0)

  可以将委托实例化为 Func<int,bool> myFunc,其中 int 是输入参数,bool 是返回值。 始终在最后一个类型参数中指定返回值。 Func<int, string, bool> 定义包含两个输入参数(int 和 string)且返回类型为 bool 的委托。 在调用下面的 Func 委托时,该委托将返回 true 或 false 以指示输入参数是否等于 5:

 

Func<int, bool> myFunc = x => x == 5;
bool result = myFunc(4); 

 

 

 
 
 
                http://archive.cnblogs.com/a/1409654/
上一篇:jQuery和UpdatePanel兼容的问题


下一篇:谈谈对css定位的理解