【IT168 技术教程】
匿名方法的由来
没有匿名方法的时候(C# 1.0)
addButton.Click += new EventHandler(AddClick);
void AddClick(object sender,EventArgs e)
{
listBox.Items.Add(textBox.Text);
}
有了匿名方法之后(C# 2.0)
addButton.Click += delegate
{
listBox.Items.Add(textBox.Text);
}
匿名方法简介
匿名方法允许我们以一种“内联”的方式来编写方法代码,将代码直接与委托实例相关联,从而使得委托实例化的工作更加直观和方便。
匿名方法的几个相关问题
- 参数列表
- 返回值
- 外部变量
匿名方法的参数
匿名方法可以在delegate关键字后跟一个参数列表(可以不指定),后面的代码块则可以访问这写参数:
addButton.Click += delegate(object sender,EventArgs e)
{
MessageBox.Show((Button)sender).Text);
}
注意:不指定参数列表与参数列表为空的区别
addButton.Click += delegate{...} // 正确
addButton.Click += delegate(0{...} // 错误
匿名方法的返回值
如果委托类型的返回值类型为void,匿名方法的便不能返回任何值;
如果委托类型的返回值类型为void,匿名方法里的返回的值必须和委托类型的返回值兼容:
delegate void MyDelegate();
MyDelegate d = delegate
{
...
return;
}
delegate int MyDelegate();
MyDelegate d = delegate
{
...
return 100;
}
匿名方法的外部变量
一些局部变量和参数有可能被匿名方法所使用,它们被称为“匿名方法的外部变量”。
外部变量的生存周期会由于“匿名方法的捕获效益”而延长 - 一直延长到委托实例不被引用为止。
static void Foo(double factor)
{
Function f = delegate(int x)
{
facator += 0.2; // factor为外部变量
return x*factor;
};
Invoke(f); // factor的生存周期被延长
}
委托类型的推断
C# 2.0允许我们在进行委托实例化时,省略掉委托类型,而直接采用方法名,C#编译器会做合理的推断。
C# 1.1中的做法:
addButton.Click += new EventHandler(AddClick);
Apply(a,new Function(Math.Sin);
C# 2.0中的做法:
addButton.Click += AddClick;
Apply(a,Math.Sin);
匿名方法的机制
C# 2.0中的匿名方法仅仅是通过编译器的一层额外处理,来简化委托实例化的工作。它与C# 1.0的代码不存在根本性的差别。
通过ILDasm.exe反汇编工作,我们可以获得对匿名方法的深入了解:
- 静态方法中的匿名方法
- 实例方法中的匿名方法
- 匿名方法中的外部变量
静态方法中的匿名方法
public delegate void D();
static void F()
{
D d = delegate{Console.WriteLine("text");};
}
上面的代码被编译器转换为:
static void F()
{
D d = new D(Method1);
}
static void _Method1()
{
Console.WriteLine("test");
}
实例方法中的匿名方法
class Test
{
int x;
void F()
{
D d = delegate{Console.WriteLine(this.x);};
}
}
上面的代码被编译器转换为:
void F()
{
D d = new D(Method1);
}
void _Method1()
{
Console.WriteLine(this.x);
}
匿名方法的外部变量
void F()
{
int y = 123;
D d = delegate{Console.WriteLine(y);};
}
上面的代码被编译器转换为:
class _Temp
{
public int y;
public void _Method1()
{
Console.WriteLine(y);
}
}
void F()
{
_Temp t = new _Temp();
t.y = 123;
D d = new D(t._Method1);
}