来源:杂烩
搜集整理:sagahu@163.com 日期:2012-01-04
匿名方法是C#2.0引入的一个新特性,它允许开发者内联(inline)声明自己的函数代码而无须使用委托函数(delegate function)。
匿名方法通常在:(1) 需要一个临时方法,该方法使用次数极少;(2) 这个方法的代码很短,甚至可能比方法声明都短的情况下使用。
在C# 1.1里,声明和使用委托要求你有委托和一个在委托被触发时具有匹配签名的能够执行的命名方法,以及一个将命名方法与委托关联的分配语句——这是C#2.0之前版本中,实例化委托的唯一方法。作为C# 2.0的新特性,匿名方法基本上能够提供与先前命名方法相同的功能,但是它已经不再需要一个在关联到委托之前就明确创建的方法了。你可以把C# 匿名方法想象为一个实现与委托进行关联这项功能的便捷途径。
如果同时看一下匿名方法实现和命名方法实现所取得IL结果,你会发现这两者之间的差别非常小。当编译器碰到匿名方法的时候,它会在类里面创建一个命名方法,并将它与委托进行关联。所以匿名方法在运行期间与命名方法的性能非常类似——性能的增加体现在开发人员的生产效率上,而不是运行期间的执行上。
在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式。 不过,本主题中有关匿名方法的信息同样也适用于 Lambda 表达式。 有一种情况下,匿名方法提供了 Lambda 表达式中所没有的功能。 您可使用匿名方法来忽略参数列表。 这意味着匿名方法可转换为具有各种签名的委托。 这对于 Lambda 表达式来说是不可能的。
一、实例化委托的两种方法
下面的示例演示实例化委托的两种方法:
- 使委托与匿名方法关联。
- 使委托与命名方法关联。
两种方法都会在调用委托时显示一条消息。
class Program
{
// 声明一个委托。
// Declare a delegate.
delegate void Printer(string s);
static void DoWork(string k)
{
Console.WriteLine(k);
}
static void Main(string[] args)
{
// 这段代码演示使用命名方法来实例化委托
// The delegate instantiation using a named method "DoWork".
Printer p = new Printer(Program.DoWork);
// Results from the old style delegate call.
p("The delegate using the named method is called.");
// 这段代码演示使用匿名方法来实例化委托
// Instatiate the delegate type using an anonymous method.
p = delegate(string j)
{
System.Console.WriteLine(j);
};
// Results from the anonymous delegate call.
p("The delegate using the anonymous method is called.");
}
}
/* 输出:
* Output:
The delegate using the anonymous method is called.
The delegate using the named method is called.
*/
关于语法规则:
- 匿名方法总是以一个delegate关键字开始,后面跟着用在方法和方法体(the method body)本身中的参数。
- 用户不需要确定匿名方法的返回类型,返回类型由方法体中的return语句推断而来。
接下来,是笔者参考网文《C# 2.0匿名方法揭密 》进行修订,以更加深入学习匿名方法。
二、再次体验匿名方法
在下面这个例子里,我们给出一个名为MyCollection的集合,它有个string[] GetFilteredItemArray(SelectItem itemFilter)方法,可以获得集合中满足由用户通过SelectItem itemFilter委托提供过滤准则的项目。嗯,这个方法的参数是个委托,就是说它的具体内容由调用者来通过方法实现。
public class MyCollection
{
public delegate bool SelectItem(string sItem);
public string[] GetFilteredItemArray(SelectItem itemFilter)
{
List <string> sList = new List<string>();
foreach (string sItem in m_sList)
{
if (itemFilter(sItem) == true) sList.Add(sItem);
}
return sList.ToArray();
}
public List<string> ItemList
{
get
{
return m_sList;
}
}
private List<string> m_sList = new List<string>();
}
下面代码用命名方法来实现这个委托调用。
class Program
{
public static void Main(string[] args)
{
MyCollection objMyCol = new MyCollection();
objMyCol.ItemList.Add("Aditya");
objMyCol.ItemList.Add("Tanu");
objMyCol.ItemList.Add("Manoj");
objMyCol.ItemList.Add("Ahan");
objMyCol.ItemList.Add("Hasi");
//获得集合中以字母’A‘开头的字符项数组
string[] AStrings = objMyCol.GetFilteredItemArray(FilterStringWithA);
Console.WriteLine("----- Strings starting with letter 'A' -----");
foreach (string s in AStrings)
{
Console.WriteLine(s);
}
//获得集合中以字母’T‘开头的字符项数组
string[] TStrings = objMyCol.GetFilteredItemArray(FilterStringWithT);
Console.WriteLine("----- Strings starting with letter 'T' -----");
foreach (string s in TStrings)
{
Console.WriteLine(s);
}
}
public static bool FilterStringWithA(string sItem)
{
if (sItem[0] == 'A')
return true;
else
return false;
}
public static bool FilterStringWithT(string sItem)
{
if (sItem[0] == 'T')
return true;
else
return false;
}
}
接下来,我们改造成用匿名方法来实现。
static void Main(string[] args)
{
MyCollection objMyCol = new MyCollection();
objMyCol.ItemList.Add("Aditya");
objMyCol.ItemList.Add("Tanu");
objMyCol.ItemList.Add("Manoj");
objMyCol.ItemList.Add("Ahan");
objMyCol.ItemList.Add("Hasi");
//获得集合中以字母’A‘开头的字符项数组
string[] AStrings = objMyCol.GetFilteredItemArray(delegate(string sItem) // 看,匿名方法返回类型不需要也不能定义
{
if (sItem[0] == 'A')
return true;
else
return false;
});
Console.WriteLine("----- Strings starting with letter 'A' -----");
foreach (string s in AStrings)
{
Console.WriteLine(s);
} //获得集合中以字母’ T ‘开头的字符项数组
string[] TStrings = objMyCol.GetFilteredItemArray(delegate(string sItem) // 匿名方法的返回类型由编译器根据方法体中return推断
{
if (sItem[0] == 'T')
return true;
else
return false;
});
Console.WriteLine("----- Strings starting with letter 'T' -----");
foreach (string s in TStrings)
{
Console.WriteLine(s);
}
}
从上面的代码中,可以看出:(1)使用匿名方法可以省去相对于使用命名方法的一些代码,可以消除类代码中小型方法的混乱。(2)匿名方法返回类型不需要也不能定义,而是由编译器根据方法体中return语句来推断得到。
注意:用这种内联代码可能看起来自然并且避免了定义新方法,但是如果这个技术被用于更大的内联代码块,这时代码很快变得难于管理并可能导致代码重复。因此,使用方法与内联匿名方法都是委托/事件处理器的可选方案。