Bootstrap

匿名方法、Lambda表达式

目录

 

一、匿名方法... 2

1、匿名方法的由来... 2

2、匿名方法的简介... 2

3、匿名方法的参数... 2

4、匿名方法的返回值... 3

5、匿名方法的外部变量... 3

6、委托类型的推断... 4

7、匿名方法的机制... 4

8、静态方法中的匿名方法... 4

9、实例方法中的匿名方法... 5

10、匿名方法中的外部变量... 5

二、Lambda表达式... 6

1、初识Lambda表达式... 6

2Lambda表达式简介... 6

3Lambda表达式格式... 6

4Lambda表达式格式要点... 7

5Lambda表达式与委托类型... 7

三、补充... 7

1、匿名方法和Lambda表达式都表示一个委托类型的对象。... 7

 

 

 正文

 

一、匿名方法

1、匿名方法的由来

没有匿名方法的时候(C#1.0

addButton.Click+=new EventHandler(AddClick);

void AddClick(object sender, EventArgs e)

{

    addButton.Text = "hello";

}

有了匿名方法之后(C#2.0

addButton.Click += delegate

{

    addButton.Text = "hello";

};

2、匿名方法的简介

匿名方法允许我们以一种“内联”的方式来编写方法代码,将代码直接与委托实例相关联,从而使得委托实例化的工作更加直观和方便。

 

匿名方法的几个相关问题:

-参数列表

-返回值

-外部变量

3、匿名方法的参数

匿名方法可以在delegate关键字后跟一个参数列表(可以不指定,但若指定必须完全匹配),后面的代码则可以访问这些参数。

addButton.Click += delegate(object sender,EventArgs e)

{

    MessageBox.Show(((Button)sender).Text);

};

 

注意“不指定参数列表”与“参数列表为空”的区别

addButton.Click += delegate { };  //正确

addButton.Click += delegate() { };  //错误

4、匿名方法的返回值

如果委托类型的返回值类型为void,匿名方法里便不能返回任何值。

 

如果委托类型的返回值类型不为void,匿名方法里返回的值必须和委托类型的返回值兼容。

 

delegate void MyDelegate();

MyDelegate d = delegate

{

    return;  //也可以不写return

};

 

delegate int MyDelegate();

MyDelegate d = delegate

{

    return 100;

};

5、匿名方法的外部变量

一些局部变量和参数有可能被匿名方法所使用,它们被称为“匿名方法的外部变量”。

 

外部变量的生存期会由于“匿名方法的捕获效益”而延长――一直延长到委托实例不被引用为止。

 

delegate double Function(int x);

static void Foo(double factor)

{

    Function f = delegate(int x)

    {

        factor += 0.2;//factor为外部变量

        return x * factor;

    };

    Invoke(f);//factor的生存期被延长

}

void Invoke(Function f)

{

    for (int i = 0; i < 5; i++)

    {

        f(i);

    }

}

6、委托类型的推断

#2.0允许我们在进行委托实例化时,省略掉委托类型,而直接采用方法名,C#编译器会做合理的推断。

 

C#1.0中的做法

delegate double Function(double a);

addButton.Click += new EventHandler(AddClick);

Apply(a, new Function(Math.Sin));

 

C#2.0中的做法

delegate double Function(double a);

addButton.Click += AddClick;

Apply(a, Math.Sin);

 

7、匿名方法的机制

C#2.0中的匿名方法仅仅是通过编译器的一层额外处理,来简化委托实例化的工作。它与C#1.0的代码不存在根本性的差别。

 

通过ILDasm.exe反汇编工具,我们可以获得对匿名方法的深入了解:

-静态方法中的匿名方法

-实例方法中的匿名方法

-匿名方法中的外部变量

8、静态方法中的匿名方法

public delegate void D();

static void F()

{

    D d = delegate { Console.WriteLine("test"); };

}

上面的代码将被编译器转换为:

static void F()

{

    D d = new D(__method1);

}

static void __method1()

{

    Console.WriteLine("test");

}

9、实例方法中的匿名方法

public delegate void D();

void F()

{

    D d = delegate { Console.WriteLine("test"); };

}

上面的代码将被编译器转换为:

void F()

{

    D d = new D(__method1);

}

void __method1()

{

    Console.WriteLine("test");

}

10、匿名方法中的外部变量

public delegate void D();

void F()

{

    int y = 123;

    D d = delegate { Console.WriteLine(y); };

}

上面的代码被编译器转换为:

class __Temp

{

    public int y;

    public int __Method1()

    {

        Console.WriteLine(y);

    }

}

void F()

{

    __Temp t = new __Temp();

    t.y = 123;

    D d = new D(t.__Method1);

}

 

二、Lambda表达式

1、初识Lambda表达式

使用C#1.0查找“内部包含abc子串的所有字符串”:

delegate bool MyDelegate(string s);

 

MyDelegate d = new MyDelegate(__Method1);

list.FindAll(d);

 

bool __Method1(string s)

{

    return s.IndexOf("abc") >= 0;

}

使用C#2.0中的匿名方法查找“内部包含abc子串的所有字符串”:

list.FindAll(

    delegate(string s)

    {

        return s.IndexOf("abc") >= 0;

    }

);

使用C#3.0中的Lambda表达式查找“内部包含abc子串的所有字符串”:

list.FindAll(s => s.IndexOf("abc") >= 0);

2Lambda表达式简介

C#2.0的匿名方法允许我们以内联的方式来实现委托实例,而C#3.0Lambda表达式允许我们使用一种更接近人的思维、更自然的方式来实现类似于匿名方法同样的效果。

3Lambda表达式格式

Lambda表达式格式为:

(参数列表)=>表达式或者语句块

 

可以有多个参数、一个参数,或者无参数。参数类型可以隐式或者显示。例如:

(x, y) => x * y;                //多参数,隐式类型=>表达式

x => x * 10;                    //单参数,隐式类型=>表达式

x => { return x * 10; };        //单参数,隐式类型=>语句块

(int x) => x * 10;              //单参数,显示类型=>表达式

(int x) => { return x * 10; };  //单参数,显示类型=>语句块

() => Console.WriteLine();      //无参数=>表达式

4Lambda表达式格式要点

Lambda表达式的参数类型可以忽略,因为可以根据使用的上下文进行推断。

 

Lambda表达式的主体(body)可以是表达式,也可以是语句块。

 

Lambda表达式传入的实参将参与类型推断,以及方法重载辨析。

 

Lambda表达式表达式和表达式体可以被转换为表达式树。

5Lambda表达式与委托类型

Lambda表达式L可以被转换为委托类型D,需要满足以下条件:

LD具有相同的参数个数。

L的参数类型要与D的参数类型相同。注意隐式类型要参与类型辨析。

D的返回值类型与L相同,无论L是表达式,还是语句块。

三、补充

1、匿名方法和Lambda表达式都表示一个委托类型的对象。

匿名方法和Lambda表达式都表示一个委托类型的对象。或者说是可以转换为委托类型的对象。

参看下例:

public class MyClass

{

    delegate int MyDelegate(int x,int y);

    static void Process(MyDelegate md) { }

    static void test()

    {

        //第一种调用方式(C#1.0)

        MyDelegate md = new MyDelegate(__Method);

        MyClass.Process(md);

        //第二种调用方式(C#2.0)匿名方法

        MyClass.Process(delegate(int x, int y) { return x * y; });

        //第三种调用方式(C#3.0)Lambda表达式

        MyClass.Process((x, y) => { return x * y; });

    }

    static int __Method(int x,int y)

    {

        return x * y;

    }}

;