曾经我们为了可以调用一个方法。必须比照这种方法定义一个对应的delegate.
原先我们定义delegate
// 托付声明 -- 定义一个签名:
delegate double MathAction(double num);
class DelegateTest
{
// 符合托付声明的常规方法
static double Double(double input)
{
return input * 2;
}
static void Main()
{
原版: // 使用一个命名方法实例化托付类型
MathAction ma = Double;
// 调用托付实例
double multByTwo = ma(4.5);
Console.WriteLine(multByTwo);
简化版1: // 再用匿名方法来实例化托付类型
MathAction ma2 = delegate(double input)
{
return input * input;
};
double square = ma2(5);
Console.WriteLine(square);
简化版2: // 最后用Lambda表达式来实例化托付类型
MathAction ma3 = s => s * s * s;
double cube = ma3(4.375);
Console.WriteLine(cube);
}
}
这个能否有更好的实现办法呢?
答案是:肯定有了.也就是有通用的delegate了。
在.NETFramework 3.5中。提供了两类通用的delegate。
假设方法有返回值,则使用Func,或者Func<>
假设方法没有返回值,则使用Action,或者Action<>
Func<T,TR>(T arg)
T
此托付封装的方法的參数类型。
TR
此托付封装的方法的返回值类型。
參数
-
arg
- 类型 T
-
- 此托付封装的方法的參数。
在使用 Func<T,TResult>托付时,不必显式定义一个封装仅仅有一个參数的方法的托付。下面演示样例简化了此代码,它所用的方法是实例化 Func<T, TResult>托付,而不是显式定义一个新托付并将命名方法分配给该托付。
使用Func<>托付,我们这样写
using System;
public classLambdaExpression
{
public static void Main()
{
Func<string, string> convert = s=> s.ToUpper();//该方法将小写字母转为大写
string name = "Dakota";
Console.WriteLine(convert(name));
}
}
Func托付是system下的全局函数,不用我们自定,系统自己定义的,供我们使用,带有多个重载.
这里我们除了使用Func托付外,还是用了Labdab表达式.这里我再谈谈这个表达式.
Lambda表达式的基础类型是泛型 Func托付之中的一个。 这样能以參数形式传递 lambda表达式,而不用显式将其分配给托付。
尤其是,由于 System.Linq命名空间中很多类型方法具有Func<T, TResult>參数,因此能够给这些方法传递 lambda表达式。而不用显式实例化 Func<T, TResult>托付。
以下一行代码将生成一个序列,当中包括 numbers 数组中在 9左側的全部元素。由于它是序列中第一个不满足条件的数字:
int[] n= { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
实例2
var firstSmallNumbers =numbers.TakeWhile((n, index) => n >= index);
此演示样例展示了怎样通过将输入參数括在括号里来指定多个输入參数。该方法将返回数字数组中的全部元素,直至遇到一个值小于其位置的数字为止。不要将 lambda运算符 (=>)与大于等于运算符 (>=)混淆。
三种托付写法对照
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace func
{
//托付声明 -- 定义一个签名:
delegate double MathAction(double num);
public class Program
{
// 符合托付声明的常规方法
static double Double(double input)
{
return input * 2;
}
static void Main(string[] args)
{
// 使用一个命名方法实例化托付类型
/*
* 写法一,须要写出专门托付的函数,还须要自己定义托付
**/
MathAction ma = Double;//注意这里千万不可有Double(),否则就成了一个返回类型。是报错的,这里是制定函数的地址,给定的是函数的地址
//调用托付
double result1 = ma(4.5);
//使用系统自己定义托付实例化托付类型
/*
* 写法二。须要写出专门托付的函数。不须要自己定义托付。使用系统托付
**/
Func<double,double> func = Double;
//调用托付
double result2 = func(4.5);
//系统托付使用lamdba进行传递參数
/*
* 写法三。不须要写出专门托付的函数。还须要自己定义托付
**/
Func<double, double> result = s=> s * 2;//写法还能够换成lamdba语句块,适应多个參数的写法
double result3=result(4.5);
Func<double,double> result4 = s =>
{
return s * 2;
};
Console.WriteLine(result1);
Console.WriteLine(result3);
Console.WriteLine(result2);
Console.WriteLine(result4(4.5));
}
}
}
效果图
相同的输出效果,可是编写代码的质量确有不同。当然了也是要对自己的问题进行负责的。lamdba的使用简化的代码。可是假设自己不是对这个非常熟悉,非常easy造成出现故障,如从着手错误的源泉。匿名函数的写法解决的这个问题。可是匿名函数却没有Lamdba简便。这就是折中方法吧。看自己更喜欢哪种了。
小结:
从Func的托付中。我们能够看出,它简化了我们自定义托付带来的繁琐。同一时候它更好的结合了Lamdba的使用。降低了自定义函数的作用。同一时候也是有缺点的,就是错误的出现不easy发现是那里。
Action托付的使用与Func雷同。这里就不在说了。希望自己的总结能够对大家有所帮助。