0x53——C#中的匿名方法

这篇文章主要参考msdn上的Anonymous Methods(C# Programming Guide)Delegates, Anonymous Methods and Lambda Expression in C#Inside C# 2.0 Anonymous Methods

考虑到用匿名方法主要是:

1、有些函数只需调用一次,所以不必要新建一个函数,这个时候就可以定义匿名函数。譬如在如下情况的时候:

Thread t = new Thread(delegate()
    {
        ...
    }
);

这里的Thread里面就需要一个函数,于是我就用了一个匿名函数(就是delegate(){...})。

2、我在一个地方要加一系列的Button,但是我不知道添加的Button的个数,这时候我就可以使用匿名函数灵活添加响应事件。

这里就简要介绍一下匿名函数的使用方法,图省事,大部分地方我就直接翻译我看的博文的内容了。

上面提到的第二篇用了正则表达式的例子来介绍匿名函数,我先说明此篇。

例子的内容是需要将字符串

!!-directory/target.aspx-!!

替换为

<a href="~/directory/target.aspx">TARGET</a>

其中流程就是:

  1. 输入一个string;
  2. 匹配!!-directory/target.aspx-!!的出现,其中directory和target可能会变;
  3. 将它们替换为上面提到的url的格式;

于是我们就定义了如下的正则表达式

Regex r = new Regex("!!-(.*?)/(.*?)-!!");

关于正则表达式的内容不是此文的重点,在此不详细说明了。然后我们就要定义一个delegate了。

所谓delegate,其实是一种类型,也就是说,是可以被作为参数传入的,或者其对象被赋值为某个method。我们定义如下的一个delegate。

 

public delegate string MatchEvaluator(

    Match match

)

 

这里就相当于定义了一个新类型MatchEvaluator(就像一个class blabla会定义一个新类blabla)。这里的MatchEvaluator就是个新类型,它必须指向一个method(类似C里面的函数指针),这个method必须是接受一个match并返回一个string的。在本文中,这个delegate的对象会被指向如下一个method

public string CreateURLS(Match m)
{
  return String.Format("<a href=\"~/{0}/{1}\">{2}</a>",
         m.Groups[1].Value,
         m.Groups[2].Value,
         m.Groups[2].Value.Replace(".aspx", "").ToUpper());
}

代码的全部如下展示:

using System;
using System.Text.RegularExpressions;
  
public partial class Delegates : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    //A string to run the Regular Expression over
    string input = @"!!-products/drives.aspx-!! !!-main/contact.aspx-!!";
  
    //Define the pattern for the Regex object
    Regex r = new Regex("!!-(.*?)/(.*?)-!!");
  
    //Declare the MatchEvaluator delegate and point it to a valid method
    MatchEvaluator me = new MatchEvaluator(CreateURLS);
  
    //Consign the result of the Regex operation to a string variable
    string output = r.Replace(input, me);
  
    //output returns <a href="~/products/drives.aspx">DRIVES</a> <a href="~/main/contact.aspx">CONTACT</a>
  }
  
  //The method that the MatchEvaluator Delegate will point to
  public string CreateURLS(Match m)
  {
    return String.Format("<a href=\"~/{0}/{1}\">{2}</a>",
           m.Groups[1].Value,
           m.Groups[2].Value,
           m.Groups[2].Value.Replace(".aspx", "").ToUpper());
  }
}

其实这里我们还没有使用匿名函数,只是使用了一个delegate,如果想使用匿名函数,代码就会变成如下这个样子,其实就是把CreateURLS揉到了main里面:

using System;
using System.Text.RegularExpressions;
  
public partial class Delegates : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    string input = @"!!-products/drives.aspx-!! !!-main/contact.aspx-!!";
    Regex r = new Regex("!!-(.*?)/(.*?)-!!");
    string output = r.Replace(input, delegate(Match m)
    {
      return String.Format("<a href=\"~/{0}/{1}\">{2}</a>",
       m.Groups[1].Value,
       m.Groups[2].Value,
       m.Groups[2].Value.Replace(".aspx", "").ToUpper());
    });
    //output returns <a href="~/products/drives.aspx">DRIVES</a> <a href="~/main/contact.aspx">CONTACT</a>
  }
}

这样我们定义MatchEvaluator就省了,直接在调Replace的时候定义了一个匿名函数。这样代码就显得更为精简。用这种方法,就可以实现上面我说到的第二天需求,即动态添加响应函数。

 

上面提到匿名方法有点像函数指针,那我下面再给一种像函数指针的使用方法。

如下的情况是我们有一堆字符串,在一个叫MyCollection的类里面,然后我们想获得其中以A打头或者T打头的字符串,分别存到连个List里面。

如下先给出MyCollection的定义。

class MyCollection
{
    private List<string> m_sList = new List<string>();

    public delegate bool SelectItem(string item);

    public string[] GetFilteredItemArray(SelectItem itemFilter)
    {
        List<string> sList = new List<string>();
        foreach (string sItem in m_sList)
        {
            if (itemFilter(sItem)) sList.Add(sItem);
        }
        return sList.ToArray();
    }

    public List<string> ItemList
    {
        get
        {
            return m_sList;
        }
    }
}

这里定义的一个SelectItem就是匿名函数,它在这里相当于筛选函数GetFilteredItemArray里的筛选器。

 

之后我们有主类Program,它实现了两个筛选函数:

class Program
{
    public static bool FilterStringWithA(string sItem)
    {
        return (sItem[0] == 'A');
    }

    public static bool FilterStringWithT(string sItem)
    {
        return (sItem[0] == 'T');
    }
}

这样我们就可以像在C里面用函数指针,如果不知道这货的话,其实就像使用变量一样调用这两个Method。

在Program里面添加static main如下:

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");

    // get an array of string items in the collection that starts with letter 'A'
    string[] AStrings = objMyCol.GetFilteredItemArray(FilterStringWithA);
    Console.WriteLine("----- Strings starting with letter 'A' -----");
    foreach (string s in AStrings)
    {
        Console.WriteLine(s);
    }

    // get an array of string items in the collection that starts with letter 'T'
    string[] TStrings = objMyCol.GetFilteredItemArray(FilterStringWithT);
    Console.WriteLine("----- Strings starting with letter 'T' -----");
    foreach (string s in TStrings)
    {
        Console.WriteLine(s);
    }

    Console.ReadLine();
}

最后的Console.ReadLine()是为了不让程序结束后立即退出添加的。

这样本文的内容就基本介绍完了。

关于匿名函数,在其他地方还同时会介绍Lambda Expression,有兴趣也可以再去看下。

 

 

posted @ 2012-04-20 10:22  cuero  阅读(391)  评论(0编辑  收藏  举报