在C# 里声明和使用委托要求你有委托和一个在委托被触发时具有匹配签名的能够执行的方法以及一个将命名方法与委托关联的分配语句作为C# 的新特性匿名方法基本上能够提供与先前命名方法相同的功能但是它已经不再需要一个在关联到委托之前就明确创建的方法了
你可以把匿名方法想象为一个实现与委托进行关联这项功能的便捷途径如果同时看一下匿名方法实现和命名方法实现所取得IL结果你会发现这两者之间的差别非常小当编译器碰到匿名方法的时候它会在类里面创建一个命名方法并将它与委托进行关联所以匿名方法在运行期间与命名方法的性能非常类似——性能的增加体现在开发人员的生产效率上而不是运行期间的执行上
如何使用匿名方法
多用代码少用说教来解释和理解匿名方法会容易一些下面的例子应该能够说明你自己可以如何利用匿名方法的优势
例——基础知识
使用匿名方法很简单你只需要把匿名方法放在你通常放命名方法的关联语句里在下面这个例子里我把匿名方法和示例的委托关联在一起
示例列表
#region Simple example Example
privatedelegatevoidExample();
privatevoid btnExample_Click(object sender EventArgs e)
{
//Declare an instance of the Example delegate
// You can see where Im using the anonymous
// method in place of a named method it follows
// the delegate() keyword
Example example =
newExample(
delegate()
{
MessageBoxShow(Example);
});
example();
}
#endregion
例——变量范围
任何在匿名方法里声明的变量的范围都不会超出匿名方法的代码块但是匿名方法确实具有访问它们代码块之外的变量的能力只要这些变量在匿名方法所使用的范围里这些变量被微软称为外部变量下面示例显示了匿名方法如何引用外部变量
示例列表
#region Variable scope example Example
privatedelegatevoidExample();
privatevoid btnExample_Click(object sender EventArgs e)
{
//Setup our parameters
string firstName = Zach;
string lastName = Smith;
//Create an instance of the Example delegate with an
// anonymous method
Example example =
newExample(
delegate() {
MessageBoxShow(firstName + + lastName);
});
//Execute the delegate
example();
}
#endregion
要注意的是根据MSDN的文档匿名方法里的ref和out参数无法被访问到
例——参数的传递
你可以将参数传递给匿名方法方式就和你处理引用命名方法参数的委托一样下面的示例说明这种类型的功能
示例列表
#region Parameter example Example
privatedelegatevoidExample(string firstName string lastName);
privatevoid btnExample_Click(object sender EventArgs e)
{
//Setup our parameters
string parameter = Zach;
string parameter = Smith;
//Create an instance of the Example delegate with an
// anonymous method
Example example =
newExample(
delegate(string firstName string lastName)
{
MessageBoxShow(Example: + firstName + + lastName);
});
//Execute the delegate
example(parameter parameter);
}
#endregion
例——多个方法的关联
就和命名方法一样将多个匿名方法与同一个委托进行关联是可能的这在很多情况下会非常有用——首先想到的是把一个简单的处理程序添加给按钮的点击事件下面的代码(示例)显示了一个委托它同时带有与之相关联一个匿名方法和一个命名方法
示例列表
#region Multiple method association (stacking) Example
privatedelegatevoidExample(string firstName string lastName);
privatevoid btnExample_Click(object sender EventArgs e)
{
//Setup our parameters
string parameter = Zach;
string parameter = Smith;
//Create an instance of the Example delegate with an
// anonymous method
Example example =
newExample(
delegate(string firstName string lastName)
{
MessageBoxShow(Example: + firstName + + lastName);
});
//Add another method to the delegate this time
// a named method
example += newExample(ExampleNamedMethod);
//Execute the delegate
example(parameter parameter);
}
privatevoid ExampleNamedMethod(string firstName string lastName)
{
MessageBoxShow(ExampleMethod: + firstName + + lastName);
}
#endregion
例——将匿名方法作为参数传递
就和命名方法一样将匿名方法作为参数传递给函数是可能的这并不是一个我认为会通常使用的特性但是我敢肯定未来会有这种需要下面的代码(例)说明了这种类型的功能它将一个命名方法作为参数传递给了函数
示例列表
#region Passing anonymous methods Example
privatedelegatevoidExample(string firstName string lastName);
privatevoid btnExample_Click(object sender EventArgs e)
{
//Execute Passit and pass the anonymous method
Passit((Example)delegate(string firstName string lastName)
{
MessageBoxShow(Example: + firstName + + lastName);
});
//Execute Passit with the named method
Passit(ExampleNamedMethod);
}
privatevoid ExampleNamedMethod(string firstName string lastName)
{
MessageBoxShow(ExampleMethod: + firstName + + lastName);
}
privatevoid Passit(Example example)
{
example(Zach Smith);
}
#endregion
例—-访问类成员
这是对上面例的变量范围的扩展但是这个例子(例)说明了匿名参数还能够在它们的代码块之外执行命名方法
示例列表
#region Accessing class members Example
privatedelegatevoidExample();
privateint _customerId;
privatestring _customerCode;
publicint CustomerID
{
get { return _customerId; }
set { _customerId = value; }
}
publicstring CustomerCode
{
get { return _customerCode; }
set { _customerCode = value; }
}
privatevoid btnExample_Click(object sender EventArgs e)
{
//Populate out properties
thisCustomerID = ;
thisCustomerCode = HK;
//Setup the delegate/anonymous method
Example example =
newExample(
delegate
{
thisShowCustomer(thisCustomerID thisCustomerCode);
});
//Execute the delegate
example();
//Change the properties
thisCustomerID = ;
thisCustomerCode = LM;
//Execute the delegate again
// Notice that the new values are reflected
example();
}
privatevoid ShowCustomer(int customerId string customerCode)
{
MessageBoxShow(
StringFormat(CustomerID: Customer Code:
customerId customerCode));
}
#endregion
要注意的是我两次调用了与匿名方法相关联的委托你可能会发现一个很有趣的事情在这些调用中方法会输出两组不同的值这是因为用在匿名方法里的外部变量在创建匿名方法的时候被引用这意味着对这些变量的任何更改都会在匿名函数访问变量的时候被反映出来
你可能还注意到在这个实例里委托关键字后面没有括号当匿名方法不需要带参数的时候后面的括号是可选的
评论
我希望本文已经说明如何使用匿名方法虽然它们还不是革命性的但是它们是C#演化成为一门程序员友好的语言过程中的一个重要步骤
(文/ZachSmith)