日期:2014-05-20  浏览次数:20698 次

LINQ(Language Integrated Query)(2):预备知识,扩展方法,Lambda

扩展方法,Lambda跟Linq一样是C#3.0出现的新特性.扩展方法和Lambda(拉姆达表达式)在Linq中使用得很多,但也可以不依托Linq在其他地方独立使用.比如Lambda在委托和事件中就用得多.

扩展方法

扩展,顾名思义就是在原有的基础上增加些啥东东.和分部类达到的效果有点类似.我们知道定义class时在前面加个partial,则可以在分开的几个文件中编写类的代码.编译时会合并成一个类.扩展方法就是你在其他任何地方定义个跟某个类相关联的静态方法后(当然和一般的方法语法有一点点区别,另外也不是真的任何地方,必须是定义在某个静态类中),就相当给原来的类新增加了一个方法.其实我们也可以通过继承一个类,新增一个函数达到类似的目的.只不过这样太麻烦了点,而且有些类是sealed的,不能继承.

举个简单例子,我们知道string类中没有Add(string str)这个方法,我们就来弄个扩展方法.让string类拥有这方法

public static class ExtensionMethods

{

 /*下面的方法就是所谓的扩展方法了.跟一般方法非常类似.只不过里面有个this关键字,this后面出现哪个类就表示这方法跟哪个类关联.

this string str表示此方法跟string类关联,str在这里不能当作普通方法中函数参数来看待.它在定义时必不可少.但在函数体中可以用至它也可以不用.另外str只是个参数名,你自然可以随便取名.除开this string str这个地方有点奇怪外.其他地方完全跟一般方法一样.你可以随便添加多少参数.*/

    public static string Add(this string str,string addStr)

        {

            return str + addStr;

           //如果不用str,也可以这样写return addStr

        }

}

有了上面的定义后你在其他任何用到string类的地方都能使用这函数了

比如

string str = "Hello ";

string newStr =  str.Add("arwen");

 

实际上我们自己写代码时用到扩展方法的时候不多.不过要是你开发第三方控件,扩展VS里面看到的那些控件的功能时肯定会大量使到扩展方法

另外Linq写好了很多扩展方法让我们可以去调用.你在命名空间System.Linq下的静态函数Enumerable中会看到很多扩展方法

于是你在引用了Linq命名空间后使用数组时会看到多出了Any,All这些奇怪的方法.

 

Lambda表达式

 

Lambda表达式本来是数学中的一个术语.在C#中代表的意思我们可以理解为把一个函数表示成有点像数学中的函数的形式.在数学中我们会看到 y = f(x)这样的函数.x表示变量,

y是返回值.我们以前在C#中要实现这样类似的功能往往是先在哪定义个函数,然后再去调用它.但现在可以直接使用函数,不用先定义再去调用.举个简单例子看下

Func<int, int, int> fun =

                                    (a, b) => a * b;

            int one = 4;

            int two = 5;

            int y = fun(one, two);

Func是一个预定义好的代理,这里我们给代理绑定一个函数.但我们不用先在其他地方定义个函数,然后再使用那函数名来调用.直接来个(a,b) =>a*b;它就是所谓的Lambda表示式了.其实就相当于是一个函数,形式比较简单,而且可以直接拿来用了.其实它也 就是个更简单的匿名方法.我们也可以用delegate关键字来表示一个匿名方法.比如上面的Lambda表达式等价于

Func<int, int, int> fun =

                delegate(int a, int b) { return a * b; };       //这个是匿名方法

 

再来说下Lambda的格式:

以=>做为分界线(一个等号加大于号,中间不能空格),前面的部分是参数,后面是函数体.(a,b)=>a*b;只是个简写形式,它的完整形式应该是

(int a,int b) => {return a*b;};

//一般情况下括号中的参数的类型都可以省略.因为通过前面的代理的参数类型可以推断出来.但如果要显式写上类型的话所有的参数就必须同时都写上

如果写成(int a,b)就错了.

 

通过扩展方法和Lambda实现通过select,where关键字实现的功能

 

string[] names = { "arwen", "james", "sunny", "lily", "ada" };

  var name   = from na in names

                         where na.StartsWith("a")

                         select na;

假如有这样的语句.则它和下面的语句等价.

var myName = names.Where(str => str.StartsWith("a"));

 

至于你两种形式你喜欢用哪一种凭你自己的爱好.我觉得通过select,where这样的关键字应该是更直观点