引用官方的话:委托 是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。
简而言之,委托就是方法参数化。类似于 Javascript 中的回调函数,也是将函数参数化的用例。至于 委托 有何妙用呢?且看下方道来!
项目准备
创建如下所示控制台应用程序:
在文件 Program.cs
中写一个求和的方法 sumFunc()
,代码如下所示:
using System;
namespace DelegateDemo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
// 委托所调用的函数
private static int sumFunc(int a, int b)
{
return a + b;
}
}
}
委托的声明、初始化以及使用
委托的声明和初始化
在使用委托之前,需要使用关键字 delegate
来对委托进行申明,委托的申明可以通过以下几种方式进行:
1. 最早的申明方式,在 C# 1.0 及更高版本可以使用以下示例进行申明:
class Program
{
// 申明委托 GetSum,委托修饰符:delegate
private delegate int GetSum(int a, int b);
static void Main(string[] args)
{
// 实例化委托 sum
GetSum sum = new GetSum(sumFunc);
Console.ReadLine();
}
// 委托所调用的函数
private static int sumFunc(int a,int b)
{
return a+b;
}
}
2. 自 C# 2.0 以后 C# 提供了一种简单的申明实例化方式:
class Program
{
// 申明委托 GetSum,委托修饰符:delegate
private delegate int GetSum(int a, int b);
static void Main(string[] args)
{
// 实例化委托 sum。差别在这里 ↓
GetSum sum = sumFunc;
Console.ReadLine();
}
// 委托所调用的函数
private static int sumFunc(int a, int b)
{
return a + b;
}
}
3. 还可以通过 匿名函数 的形式来声明和初始化委托,如下所示:
class Program
{
// 申明委托 GetSum,委托修饰符:delegate
private delegate int GetSum(int a, int b);
static void Main(string[] args)
{
// 实例化委托 sum。差别在这里 ↓
GetSum sum = delegate (int a, int b) { return a + b; };
Console.ReadLine();
}
}
4. 还可以通过 lambda 表达式的方式申明和实例化委托,如下所示:
class Program
{
// 申明委托 GetSum,委托修饰符:delegate
private delegate int GetSum(int a, int b);
static void Main(string[] args)
{
// 实例化委托 sum。差别在这里 ↓
GetSum sum = (a, b) => { return a + b; };
Console.ReadLine();
}
}
委托的使用示例
示例一:
class Program
{
// 申明委托 GetSum,委托修饰符:delegate
private delegate int GetSum(int a, int b);
static void Main(string[] args)
{
// 实例化委托 sum。
GetSum sum = sumFunc;
// 使用委托
int _sum = sum(3, 4);
Console.WriteLine($"计算结果:{_sum}");
Console.ReadLine();
}
private static int sumFunc(int a, int b)
{
return a + b;
}
}
方式二: 创建一个计算乘法的函数法,计算出 (a+b)*a
的值。
class Program
{
// 申明委托 GetSum,委托修饰符:delegate
private delegate int GetSum(int a, int b);
static void Main(string[] args)
{
// 实例化委托 sum。
GetSum sum = sumFunc;
// 使用委托
int _multiply = multiplyFunc(sum, 3, 4);
Console.WriteLine($"计算结果:{_multiply}");
Console.ReadLine();
}
private static int sumFunc(int a, int b)
{
return a + b;
}
private static int multiplyFunc(GetSum sum, int a, int b)
{
return sum(a, b) * a;
}
}
委托的合并
委托可以合并多个方法,也可以移除合并方法中的其中之一。可通过 +
、 -
进行委托的绑定和移除。建立如下示例代码:
class Program
{
// 申明委托 GetSum,委托修饰符:delegate
private delegate void Execution();
static void Main(string[] args)
{
// 实例化委托 sum。
Execution fun = Func1;
fun += Func2;
fun += Func3;
Console.WriteLine("委托执行结果:");
fun();
fun -= Func2;
Console.WriteLine("移除的执行结果:");
fun();
Console.ReadLine();
}
private static void Func1()
{
Console.WriteLine("函数 Func1() 执行。");
}
private static void Func2()
{
Console.WriteLine("函数 Func2() 执行。");
}
private static void Func3()
{
Console.WriteLine("函数 Func3() 执行。");
}
}
这里合并到一起的那几个方法会根据顺序依次执行,执行结果如下:
委托执行结果:
函数 Func1() 执行。
函数 Func2() 执行。
函数 Func3() 执行。
移除的执行结果:
函数 Func1() 执行。
函数 Func3() 执行。
类库中的委托
MSCorLib.dll中,有将近50个委托类型:
public delegate void TryCode(object userData);
public delegate void WaitCallback(object state);
public delegate void TimerCallback(object state);
public delegate void ContextCallback(object state);
......
17个Action委托,其中包含16个泛型委托:
public delegate void Action();
public delegate void Action<T>(T arg);
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
......
public delegate void Action<T1,....., T16>(T1 arg1,......, T16 arg16);
Func委托,允许回调方法返回值:
public delegate TResult Func<TResult>();
public delegate TResult Func<T, TResult>(T arg);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
......
public delegate TResult Func<T1,....., T16, TResult>(T1 arg1,....., T16 arg16);
实践案例
这里我将在项目中演示主线程中调用子线程中的值(同样,子线程也可以调用主线程中的值),通过此示例,我们可以进行一些事件的开发。示例代码如下:
class Program
{
// 申明委托 GetSum,委托修饰符:delegate
private delegate string del();
static void Main(string[] args)
{
// 定义一个多线程
Thread thread = new Thread(setStr);
// 开始执行多线程
thread.Start();
// 等待这个线程执行 3S,再去执行下方代码,以确保变量 str 已经被赋值
Thread.Sleep(3000);
// 实例化委托
del _del = getStr;
// 执行委托并打印出结果
Console.WriteLine($"获取的字符串:{_del()}");
Console.ReadLine();
}
private static string str="";
private static void setStr()
{
str = "设置的字符串!";
}
private static string getStr()
{
return str;
}
}