在用委托操作方法的时候,往往创建委托的语句离操作方法的代码很远。而匿名方法正好相反,它以“in-line”的方式是委托以及所联系的代码放在了一起。除了这个方便之处,匿名方法还共享了对包含的函数成员的本地状态的存取(anonymous methods have shared access to the local state of the containing function member)。为了使用命名的方法达到共享相同的状态的目的,就需要把本地变量“拎”到手动创建的帮助类(instances of manually authored helper classes)的实例中的field里。
下面这个例子使我们在WinForm程序中最常见到的一个模式:
虽然操作方法只有一个语句,但是我们还是要手动创建EventHandler委托,已经包含所有参数的事件处理方法,并且它们是分开的。
而使用匿名方法,我们就可以这样:
由于在操作方法内部没有用到参数,我们就没省略了参数列表。如果用到了就需要写上,就像这样:
在这个例子里,发生了一个隐式转换(从匿名方法转换到EventHandler委托类型-Click事件的类型),这个隐式转换能够成功,也许是因为委托类型的返回类型跟参数列表根匿名方法是兼容的。
关于兼容性的确切规则是这样的:
如果以下某一个成立,委托的参数列表跟匿名方法兼容:
1、匿名方法没有参数列表,委托没有out参数。
2、匿名方法包含的参数列表恰好在数量、类型、修饰符各方面匹配委托的参数。
如果以下某一个成立,委托的返回类型跟匿名方法兼容:
1、委托的返回类型是void,匿名方法没有return语句,或者只有return语句而不带表达式。
2、委托的返回类型不是void,关联于匿名方法的return语句的表达式能够隐式转换为委托的返回类型。
而隐式转换必须满足上面两个都满足才能发生。
再给一个例子:
下面这个例子使我们在WinForm程序中最常见到的一个模式:
class InputForm: Form
{
ListBox listBox;
TextBox textBox;
Button addButton;
public MyForm() {
listBox = new ListBox();
textBox = new TextBox();
addButton = new Button();
addButton.Click += new EventHandler(AddClick);
}
void AddClick(object sender, EventArgs e) {
listBox.Items.Add(textBox.Text);
}
}
{
ListBox listBox;
TextBox textBox;
Button addButton;
public MyForm() {
listBox = new ListBox();
textBox = new TextBox();
addButton = new Button();
addButton.Click += new EventHandler(AddClick);
}
void AddClick(object sender, EventArgs e) {
listBox.Items.Add(textBox.Text);
}
}
虽然操作方法只有一个语句,但是我们还是要手动创建EventHandler委托,已经包含所有参数的事件处理方法,并且它们是分开的。
而使用匿名方法,我们就可以这样:
class InputForm: Form
{
ListBox listBox;
TextBox textBox;
Button addButton;
public MyForm() {
listBox = new ListBox();
textBox = new TextBox();
addButton = new Button();
addButton.Click += delegate {
listBox.Items.Add(textBox.Text);
};
}
}
{
ListBox listBox;
TextBox textBox;
Button addButton;
public MyForm() {
listBox = new ListBox();
textBox = new TextBox();
addButton = new Button();
addButton.Click += delegate {
listBox.Items.Add(textBox.Text);
};
}
}
由于在操作方法内部没有用到参数,我们就没省略了参数列表。如果用到了就需要写上,就像这样:
addButton.Click += delegate(object sender, EventArgs e) {
MessageBox.Show(((Button)sender).Text);
};
MessageBox.Show(((Button)sender).Text);
};
在这个例子里,发生了一个隐式转换(从匿名方法转换到EventHandler委托类型-Click事件的类型),这个隐式转换能够成功,也许是因为委托类型的返回类型跟参数列表根匿名方法是兼容的。
关于兼容性的确切规则是这样的:
如果以下某一个成立,委托的参数列表跟匿名方法兼容:
1、匿名方法没有参数列表,委托没有out参数。
2、匿名方法包含的参数列表恰好在数量、类型、修饰符各方面匹配委托的参数。
如果以下某一个成立,委托的返回类型跟匿名方法兼容:
1、委托的返回类型是void,匿名方法没有return语句,或者只有return语句而不带表达式。
2、委托的返回类型不是void,关联于匿名方法的return语句的表达式能够隐式转换为委托的返回类型。
而隐式转换必须满足上面两个都满足才能发生。
再给一个例子:
using System;
delegate double Function(double x);
class Test
{
static double[] Apply(double[] a, Function f) {
double[] result = new double[a.Length];
for (int i = 0; i < a.Length; i++) result[i] = f(a[i]);
return result;
}
static double[] MultiplyAllBy(double[] a, double factor) {
return Apply(a, delegate(double x) { return x * factor; });
}
static void Main() {
double[] a = {0.0, 0.5, 1.0};
double[] squares = Apply(a, delegate(double x) { return x * x; });
double[] doubles = MultiplyAllBy(a, 2.0);
}
}
delegate double Function(double x);
class Test
{
static double[] Apply(double[] a, Function f) {
double[] result = new double[a.Length];
for (int i = 0; i < a.Length; i++) result[i] = f(a[i]);
return result;
}
static double[] MultiplyAllBy(double[] a, double factor) {
return Apply(a, delegate(double x) { return x * factor; });
}
static void Main() {
double[] a = {0.0, 0.5, 1.0};
double[] squares = Apply(a, delegate(double x) { return x * x; });
double[] doubles = MultiplyAllBy(a, 2.0);
}
}
其中,Apply方法把一个给定的Function应用于一个double数组a,返回也是一个double数组。在主函数里,Apply的第一个参数是一个匿名方法,这个匿名方法是跟Function委托兼容的。在方法里,我们只是简单的返回double值x的平方。
在MultiplyAllBy方法里,我们为double数组的每一个double值乘上了一个系数,而方法内部,是使用匿名方法达到所需要的操作的。
在生存范围里包含匿名方法的本地变量和参数叫做匿名方法的outer variables。在MultiplyAllBy方法里,a和factor是匿名方法的outer variables,传递给了Apply,由于匿名方法引用了factor,factor就被说成被匿名方法捕获了:)一般来说,本地变量的生存期限制于所关联的block,然而,被捕获的本地变量的生存周期就被延长了,延长到指向匿名方法的委托符合垃圾回收的条件为止。
PS:
像我也是刚接触匿名方法,还真有点不习惯,可能表述上会有些问题,还请各位不吝赐教.