日期:2010-12-18  浏览次数:20453 次

  匿名方法基础

  匿名方法是C#2.0的一个新的语言特性。本文的主要内容是提供给读者关于匿名方法的内部实现和工作方式的一个更好的理解。本文无意于成为匿名方法的完全语言特性参考。

  匿名方法允许我们定义委托对象可以接受的代码块。这个功能省去我们创建委托时想要传递给一个委托的小型代码块的一个额外的步骤。它也消除了类代码中小型方法的混乱。让我们看看:比方说,我们有一个字符串集合命名为MyCollection。这个类有一个方法:获得集合中满足用户提供的过滤准则的所有项,调用者决定在集合中的一个特殊项是否符合条件而被检索到,作为从此方法返回数组的一部分。

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>();
}

  我们可以用上面定义的类写如下所示的代码:

public 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;
 }
}

  可以看出对于每个我们想要提供的简单过滤准则,我们应该定义一个方法(静态或实例的)。这很快就搞乱了类的代码。而用匿名方法,代码变得相当自然。下面是这个Program类用匿名方法重写后的:

public class Program
{
 public delegate void MyDelegate();
 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(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)
  {
   if (sItem[0] == ''T'')
    return true;
   else
    return false;
  });
  Console.WriteLine("----- Strings starting with letter ''T'' -----");
  foreach (string s in TStrings)
  {
   Console.WriteLine(s);
  }
 }
}


  正如上面示例中的所示,我们已能用内联代码块定义的过滤准则替代定义一个新的方法来代表每个过滤准则。老实说,用这种内联代码可能看起来自然并且避免了定义新方法,但是如果这个技术被用于更大的内联代码块,这时代码很快变得难于管理并可能导致代码重复。因此,使用方法与内联匿名方法都是委托/事件处理器的可选方案。

  好了,这些就是匿名方法的基础。本文的余下部分将讨论在不同的场景下匿名方法内部如何工作的。理解匿名方法如何被实现和内部如何工作对于正确地使用它们是重要的。否则,你使用匿名方法的代码的结果看起来将不可预知。

  匿名方法的静态数据成员的用法

  匿名方法总是以一个delegate关键字开始,后面跟着用在方法和方法体(the method body)本身中的参数。正如从上面示例中所见,用户不需要确定匿名方法的返回类型。它(译注:指返回类型)由方法体中的return语句推断而来。.NET CLR不能执行像匿名方法一样的自由流(free flowing)代码块。CLR要求:它执行的每个方法是一个类型的一部分,并且应该是一个静态(static)方法或实例(instance)方法(译注:若一个方法声明中含有 static 修饰符,则称该方法为静态方法。若其中没有 static 修饰符时,则称该方法为实例方法。静态方法不对特定实例进行操作,在静态方法中引用 this 是编译时错误。实例方法对类的某个给定的实例进行操作,而