C#委托 (Delegate) 详细讲解
目录
1.委托
委托(Delegate)是一个非常重要的概念,但有时候理解起来可能有些抽象。为了通俗易懂地解释委托,我们可以使用日常生活中的一个类比。
想象一下,你是一家公司的老板,你需要找人来完成一些特定的任务,比如打印文件、发送邮件等。但是,你并不直接管理这些任务的具体执行者,而是通过一个“中介”来安排。这个“中介”知道谁能做什么任务,并在需要的时候将任务分配给相应的人。
在C#中,委托就像是这个“中介”的角色。它定义了一个方法签名(即方法的返回类型和参数类型),并允许你将任何符合这个签名的方法赋值给它。然后,你可以像调用普通方法一样调用这个委托,而委托则会根据它当前所引用的方法来执行相应的代码。换句话说,委托是一个类型安全的、面向对象的函数指针。它允许你将方法作为参数传递给其他方法,或者将方法赋值给变量,从而实现了方法的动态调用。
2.委托的基本使用
为了更具体地说明,我们可以看一个简单的例子:
static void Main(string[] args)
{
//【3】定义委托变量
LectureDelegate1 lecture1 = null;
//【4】将具体方法与委托变量关联
lecture1 = ChangLecture1;
lecture1 += ZhangLecture1;
lecture1 += WangLecture1;
//【5】使用委托变量
lecture1();
//lecture1.Invoke();//委托特有的Invoke();
//可选择移除方法的关联
lecture1 -= WangLecture1;
lecture1();
LectureDelegate2 lecture2 = CangLecture2;
Console.WriteLine(lecture2(5, "sad"));
}
//【2】根据委托编写方法
static void ChangLecture1()
{
Console.WriteLine("我们正在学习委托技术");
}
static void ZhangLecture1()
{
Console.WriteLine("我们正在学习C#技术");
}
static void WangLecture1()
{
Console.WriteLine("我们正在学习.net技术");
}
static string CangLecture2(int count,string course)
{
return $"李老师主讲的是{course},课时为{count}";
}
//【1】定义委托
public delegate void LectureDelegate1();
public delegate string LectureDelegate2(int num,string num2);
可知使用委托最重要的步骤为:
- 定义委托
- 编写要委托的方法
- 定义委托变量
- 将方法与委托变量关联
- 使用委托变量
3.为什么要使用委托?
使用委托(Delegate)在编程中,特别是在C#这样的面向对象语言中,有几个非常实用的理由。为了通俗易懂地解释这些理由,我们可以借助一些日常生活中的场景。
-
像中介一样工作:
想象一下你是一位雇主,需要找人来完成某项任务,比如装修房子。但你可能并不认识所有的装修师傅,也不知道哪位最适合你的需求。这时,你可以找一个装修中介,告诉他们你的需求,中介会为你找到合适的装修师傅。
在C#中,委托就像这个装修中介。它允许你定义一个任务的签名(比如需要哪些参数,返回什么类型),然后你可以将任何符合这个签名的方法“委托”给它。当你需要执行这个任务时,你只需要告诉委托,委托就会为你找到并调用正确的方法。
- 实现代码的灵活性:
如果你正在编写一个程序,其中某个部分需要在不同的条件下执行不同的代码,那么使用委托可以让代码更加灵活。比如你正在编写一个游戏,其中玩家可以选择不同的角色。每个角色都有自己的攻击方式。你可以为每个角色的攻击方式定义一个方法,并将这些方法委托给同一个变量。这样,在玩家选择角色后,你只需要调用这个委托变量,就可以执行相应角色的攻击方式了。
-
事件处理:
在C#中,事件处理是通过委托来实现的。比如,在Windows Forms应用程序中,当你点击一个按钮时,就会触发一个点击事件。这个事件是通过一个委托来与事件处理程序(即响应点击事件的方法)关联的。想象一下你正在使用一个遥控器来控制电视。当你按下某个按钮时,遥控器就会发送一个信号给电视。电视接收到信号后,就会执行相应的操作(比如切换频道)。在这里,遥控器发送的信号就像是事件,而电视执行的操作就像是事件处理程序。委托就是用来将信号与操作关联起来的。
-
多播:
委托还支持多播,这意味着你可以将多个方法关联到同一个委托实例上。当调用这个委托时,它会依次执行所有关联的方法。这就像是你在一个聚会上邀请了多位朋友。当你宣布聚会开始时,每位朋友都会听到并做出反应(比如欢呼、跳舞等)。在这里,你宣布聚会开始就像是调用委托,而每位朋友做出的反应就像是关联到委托上的方法。
4.委托的实战应用:在多窗体通信中的使用
要实现如图所示,每个子窗体发送的消息主窗体都能识别出来并显示。

主窗体代码如下:
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
//这个集合主要是为了关闭窗体使用
private List<Form> frmList = new List<Form>();
//【1】第2步:根据委托编写具体方法
private void ReceiveMsg(string msg, string childName)
{
this.txtContent.Text = $"来自:{childName}的消息:{msg}\n";
}
//创建多个子窗体
private void btnCreateChildForm_Click(object sender, EventArgs e)
{
for(int i = 0; i < 3; i++)
{
FrmChild child = new FrmChild($"B子窗体:{i + 1}");
//【1】第四步:将委托变量与方法关联
child.passMsg += ReceiveMsg;
child.Show(this.txtSend);
}
}
//清空消息
private void btnClear_Click(object sender, EventArgs e)
{
this.txtContent.Clear();
}
//关闭全部
private void btnCloseAll_Click(object sender, EventArgs e)
{
for(int i = 0; i < 3; i++)
{
frmList[i].Close();
}
}
子窗体代码如下:
//【1】第3步:创建委托变量
public PassMsgDelegate passMsg;
public FrmChild(string childName)
{
InitializeComponent();
this.Text = childName;
}
//发送消息
private void btnSend_Click(object sender, EventArgs e)
{
//【1】第5步:使用委托变量来调用所关联的方法
passMsg(this.txtSendMsg.Text,this.Text);
}
Main方法如下:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmMain());
}
5.事件(和委托比较)
5.1事件
想象一下,你的公司经常需要组织会议,但每次组织会议的人可能不同。你不希望每次有人需要组织会议时,都直接来找你这个经理,因为这样你会很忙。于是,你设立了一个“事件”(Event),比如“需要组织会议时”。当这个事件发生时,任何注册了这个事件的人(即订阅者)都可以被通知并执行组织会议的任务。
C#中,事件是基于委托的,但它增加了一层封装。事件只允许外部代码“订阅”或“取消订阅”这个事件,而不能直接“触发”它(除非通过提供的方法)。这样,事件提供了一种发布/订阅模式,让代码更加模块化、解耦。
// 定义一个委托类型
public delegate void OrganizeMeetingHandler();
// 定义一个类,它有一个事件
public class MeetingManager
{
// 声明事件
public event OrganizeMeetingHandler MeetingNeeded;
// 触发事件的方法(通常只在类的内部调用)
protected virtual void OnMeetingNeeded()
{
MeetingNeeded?.Invoke();
}
}
// 订阅事件的方法
public void SubscribeToMeeting(MeetingManager manager)
{
manager.MeetingNeeded += OrganizeMeeting;
}
// 之前定义的组织会议的方法
public void OrganizeMeeting()
{
Console.WriteLine("Meeting is being organized.");
}
// 在某处调用
public void SomeMethod()
{
MeetingManager manager = new MeetingManager();
SubscribeToMeeting(manager);
manager.OnMeetingNeeded(); // 这将触发事件,调用OrganizeMeeting方法
}
- 委托:是一种类型,定义了方法的签名,并允许你将方法作为参数传递。你可以把委托想象成“能够执行特定任务的人”。
- 事件:是基于委托的,但它提供了一层封装,让外部代码只能订阅或取消订阅事件,而不能直接触发它。事件提供了一种发布/订阅模式,有助于代码的解耦和模块化。你可以把事件想象成“当某件事情发生时,通知所有关心这件事的人”。
更多推荐

所有评论(0)