delegate委托对于初学者来说不太好理解。
按笔者的经验,delegate本质是函数指针,可以把它理解为某一类方法的入口,把他翻译为:“长得像XXX的函数方法(入参是什么、返回值是什么)”可能更容易理解。
以下示例是delegate的写法列举:
//步骤一 声明委托
public delegate string SayHelloDelegate(string name);
internal class Program
{
static void Main(string[] args)
{
//步骤二 初始化/赋值
//写法1
SayHelloDelegate sayHello1 = MySayHello;
//写法变种2
SayHelloDelegate sayHello2 = delegate (string name) { return "Hello " + name; };
//写法变种3
SayHelloDelegate sayHello3 = (string name) => { return "Hello " + name; };
//写法变种4
SayHelloDelegate sayHello4 = name => { return "Hello " + name; };
//写法变种5
SayHelloDelegate sayHello5 = name => "Hello " + name;
//步骤三 调用
var msg = sayHello1("foolishsunday");//sayHello2("foolishsunday");//sayHello3("foolishsunday");//sayHello4("foolishsunday");//sayHello5("foolishsunday");
Console.WriteLine(msg);
//由于delegate的使用每次都需要步骤一声明委托,因此微软添加了语法糖Func和Action,把步骤一和二合并在一块写
//Func示例
Func<string, string> funcHello1 = MySayHello;
Func<string, string> funcHello2 = (string name) => { return "Hello " + name; };
Func<string, string> funcHello3 = name => { return "Hello " + name; };
Func<string, string> funcHello4 = name => "Hello " + name;
//调用Func
var result = funcHello1("test");
Console.WriteLine(result);
Console.ReadLine();
}
static string MySayHello(string name)
{
return "Hello " + name;
}
}
输出:
Hello foolishsunday
Hello test
可见Func的写法及多种变种写法都跟delegate如出一辙,但用Func更简化,而且Func能直观看到入参和返回值;
在实际编程中,很多情况需要把函数指针作为参数传入
因为具体函数的实现往往是变化的,但函数入口是不变(这里的函数入口指的是入参与返回值组成的函数形式)
其实delegate/Func/Action并不少见,尤其是C#底层代码,几乎随处可见
举个常见例子,linq中就大量用到Func
//Where方法的底层定义:
//其中入参就有Func<TSource, bool> predicate
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
使用Where看看
//例:查找长度为2的字符串并打印
//本例中的where方法就是需要传入一个Func<TSource, bool> predicate作为参数(e => e.Length == 2)
"a,bb,ccc".Split(',').Where(e => e.Length == 2).ToList()
.ForEach(e => Console.WriteLine(e));
//而Func<TSource, bool> predicate入参也可以因需求变更为(e => e.StartsWith("c")):查找c开头的字符串
"a,bb,ccc".Split(',').Where(e => e.StartsWith("c")).ToList()
.ForEach(e => Console.WriteLine(e));
Console.ReadLine();
总结:
- delegate有多种写法,只不过是一个比一个简化而已。
- 甚至Func/Action的出现都是为了简化delegate的写法。
- 它的本质也是一个函数指针,它可以实现函数/方法作为参数传入另一个函数方法体。
- 在学习设计模式中,我们学过:找到变化并封装之,把不变的和易变的隔离开来。
委托就很好体现了这种封装,某一类函数的入参与返回值总是不变的,它的具体实现过程是可变的。我们就可以把它提炼为一个委托。