什么是委托
委托是函数指针
的升级版
。C#使用委托来完成C/C++语言中的函数指针功能,相对于函数指针,委托能够完成更多的功能。
如果你熟悉Java的话,会发现Java既没有委托,也没有函数指针。在Java中,Java使用接口来完成这一操作,特别是Java8之后的函数式接口
,意图更明显。
使用委托可以间接调用方法。
委托滥用会造成灾难
,因此在C#中可以学学Java使用接口来完成部分委托的功能。
使用系统预定义的委托
Action
Action是没有返回值和参数列表为空的方法的委托。
class Pragram
{
static void Main(string[] args)
{
Calc calc = new Calc();
Action action = new Action(calc.PrintInfo);
// 委托调用
action.Invoke();
action(); // 简洁写法
}
}
class Calc
{
public void PrintInfo()
{
Console.WriteLine("class Calc.");
}
}
Func
Func共有17中泛型,分别用来对应不同参数列表个数的方法。
Func<out TResult>
对应的方法结构为: TResult Method(){...}
, TResult是返回值类型的泛型
Func<in T, out TResult>
⇒ TResult Method(T a){...}
Func<in T1, in T2, out TResult>
⇒ TResult Method(T1 a, T2 b){...}
…
class Pragram
{
static void Main(string[] args)
{
Calc calc = new Calc();
Func<int, int, int> func1 = new Func<int, int, int>(calc.Add);
Func<int, int, int> func2 = new Func<int, int, int>(calc.Sub);
int a = 100;
int b = 200;
int res;
res = func1(a, b); // 调用calc.Add方法
Console.WriteLine(res); // 输出300
res = func2(a, b); // 调用calc.Sub方法
Console.WriteLine(res); // 输出-100
}
}
class Calc
{
public int Add(int a, int b)
{
return a + b;
}
public int Sub(int a, int b)
{
return a - b;
}
}
自定义委托
委托的声明
委托是一种类(class),类是数据类型,所以委托也是一种数据类型。
声明的一般格式如下:
访问修饰符 delegate 返回值类型 委托名称(参数列表);
// 声明委托
public delegate void SayHi(string name);
class Pragram
{
static void Main(string[] args)
{
SayHi sayHi = new SayHi(Hi);
sayHi.Invoke("张三");
}
static void Hi(string name)
{
Console.WriteLine("Hi, {0}", name);
}
}
使用委托
一般使用委托的正确方式有回调函数
(什么是回调函数)和模板方法
(什么是模板方法)。
多播委托
public delegate void SayHi(string name);
class Pragram
{
static void Main(string[] args)
{
SayHi sayHi1 = new SayHi(Hi1);
SayHi sayHi2 = new SayHi(Hi2);
SayHi sayHi3 = new SayHi(Hi3);
sayHi1 += sayHi2;
sayHi1 += sayHi3;
sayHi1.Invoke("张三"); // sayHi2和sayHi3同样会被调用
}
static void Hi1(string name)
{
Console.WriteLine("Hi1, {0}", name);
}
static void Hi2(string name)
{
Console.WriteLine("Hi2, {0}", name);
}
static void Hi3(string name)
{
Console.WriteLine("Hi3, {0}", name);
}
}
隐式异步调用
使用委托的BeginInvoke
方法可以进行隐式异步调用。
public delegate void SayHi(string name);
class Pragram
{
static void Main(string[] args)
{
SayHi sayHi1 = new SayHi(Hi1);
SayHi sayHi2 = new SayHi(Hi2);
SayHi sayHi3 = new SayHi(Hi3);
sayHi1.BeginInvoke("张三", null, null);
sayHi2.BeginInvoke("李四", null, null);
sayHi3.BeginInvoke("王五", null, null);
}
static void Hi1(string name)
{
Console.WriteLine("Hi1, {0}", name);
}
static void Hi2(string name)
{
Console.WriteLine("Hi2, {0}", name);
}
static void Hi3(string name)
{
Console.WriteLine("Hi3, {0}", name);
}
}