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>
其中流程就是:
- 输入一个string;
- 匹配!!-directory/target.aspx-!!的出现,其中directory和target可能会变;
- 将它们替换为上面提到的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,有兴趣也可以再去看下。