您的位置:首页 > 其它

匿名方法,Lambda表达式,高阶函数

2015-04-15 11:23 148 查看
原文:匿名方法,Lambda表达式,高阶函数匿名方法

c#2.0引入匿名方法,不必创建单独的方法,因此减少了所需的编码系统开销。 常用于将委托和匿名方法关联,例如

1. 使用委托和方法关联:

this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
private void btnRefresh_Click(object sender, EventArgs e)
{
BindData();
}
2. 使用委托和匿名方法关联:
this.btnRefresh.Click += delegate(object sender, EventArgs e) { BindData(); };

毫无疑问,如果关联的方法是“一句话方法”的话,代码2更为简洁(实际上编译器在背后为我们创建了类似btnRefresh_Click的方法)。

匿名方法省略参数列表

定义匿名方法时候,参数列表是可以省略的,编译器可以根据委托的签名来确定函数的签名。例如,
delegate void Func(int x);
//带参数
Func f1= delegate (int p) { Console.Write(p); }
// 不带参数
Func f2 = delegate { Console.Write("he");} //编译器自动推断函数签名带int参数
使用不带参数的匿名方法,注意问题
一是因为没有参数,所以在方法内就不能使用参数。
二是有些情况不能使用匿名方法,有ambiguous的问题,例如
public Thread(ParameterizedThreadStart start);
public Thread(ThreadStart start);
而// public delegate void ParameterizedThreadStart(object obj);
// public delegate void ThreadStart();
所以使用
Thread thread = new Thread(
delegate { sh.LockMyself(); }
);
就会有问题
Error The call is ambiguous between the following methods or properties: 'System.Threading.Thread.Thread(System.Threading.ThreadStart)' and 'System.Threading.Thread.Thread(System.Threading.ParameterizedThreadStart)'

编译器不知道应该将delegate { }这一匿名方法还原为哪个函数,解决方法是显式给定参数列表,让编译器知道你要用那个函数:
Thread thread = new Thread(
delegate() { sh.LockMyself(); }
);

Lambda表达式:
Thread thread = new Thread(
() =>
{
sh.LockMyself();
}
);

Lambda表达式

Lambda表达式为编写匿名方法提供了更简明的函数式的句法,但结果却在编写LINQ查询表达式时变得极其有用,因为它们提供了一个非常紧凑的而且类安全的方式来编写可以当作参数来传递,在以后作运算的函数。
Lambda 表达式和 匿名方法 其实是一件事情。唯一的不同是:他们语法表现形式不同。Lambda 表达式是在语法方面的更进一步的进化。在本质上,他们是一件事情。他们的作用都是:产生方法。即:内联方法。

books是System.Collections.Generic.List类型, 即List<Book>, 有Find方法
使用匿名方法: books.Find(delegate(Book book){return book.Price < 50;});
使用Lambda表达式: books.Find(book=>book.Price<50);
book是输入参数; =>读作Go to,是Lambda操作符;book.Price<50是表达式或者语句块。
Lambda表达式中的输入参数省略参数类型,因为当前Find扩展方法对象是books,编译器会自动推断book参数属于BooK类型.
对比另一个例子:
// 使用匿名方法
string[] list = new string[] { "abc", "12", "java" };
string[] alist = Array.FindAll(list,
delegate(string s)
{
return s.IndexOf("a") >= 0;
}
);
foreach (string var in alist)
{
Console.WriteLine(var);
}

// 使用Lambda表达式
string[] list = new string[] { "abc", "12", "java" };
string[] alist = Array.FindAll(list, s => (s.IndexOf("a") >= 0));

Lambda表达式式范例:
//x的类型省略了,编译器可以根据上下文推断出来,后面跟着的是表达式
x => x+1
deleage(int x){return x+1;}
//后面跟着的是语句块
x=>{return x+1;}
delegate(int x){return x+1;}
//输入参数也可以带类型,带类型后别忘记小括号哦
(int x) => x+1
delegate(int x){return x+1;}
//也可以多个输入参数,逗号分隔,别忘记小括号
(x,y) => x+y
delegate(int x,int y){return x+y;}
//无参的也行
() => 1
delegate(){return 1;}

高阶函数(higher-order function)

是指把另一个函数作为参数或返回值的函数。
例如在System.Array类中就有许多静态的高阶函数,其中的ConvertAll方法可谓是最常用的高阶函数之一了:

private static DateTime StringToDateTime(string s) {
return DateTime.ParseExact(s, "yyyy-MM-dd", null);
}

static void Main(string[] args) {
string[] dateStrings = new string[] {
"2009-01-01", "2009-01-02", "2009-01-03",
"2009-01-04", "2009-01-05", "2009-01-06",
};
// ConvertAll将一个数组映射为另一个数组, new Converter是构建一个委托对象
// 类似于 new System.EventHandler(this.btnRefresh_Click);
DateTime[] dates = Array.ConvertAll<string, DateTime>(
dateStrings, new Converter<string, DateTime>(StringToDateTime));
}

// C# 2.0中,又引入了匿名方法这一构建委托对象的方式:

DateTime[] dates = Array.ConvertAll<string, DateTime>(
dateStrings,
delegate(string s) {
return DateTime.ParseExact(s, "yyyy-MM-dd", null);
});

// 新增了Lambda表达式和扩展方法等语言特性,再加上范型类型的自动判断,在C# 3.0中使用匿名方法更是异常简洁,甚至与ruby的语法如出一辙
IEnumerable<DateTime> dates = dateStrings.Select(
s => DateTime.ParseExact(s, "yyyy-MM-dd", null));

Reference
http://blog.csdn.net/shouyenet1/archive/2009/04/28/4133114.aspx
http://blog.joycode.com/scottgu/archive/2007/04/09/100744.aspx
http://www.infoq.com/cn/articles/higher-order-function
http://www.infoq.com/cn/articles/higher-order-function
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: