首先说明,event其实也是一种delegate,为了区分,我们称一般的delegate为“plain delegate”。
写代码的过程中,经常会在delegate和event之间进行选择,以前也没仔细思考选择的原因,今天终于忍不住花了半天时间仔细琢磨了一下……好了,直接拿代码说话吧:
using System;

namespace EventAndDelegate
{
public delegate void TestDelegate(string s);

public interface ITest {
// 【区别】 1. event可以用在interface中,而plain delegate不可以(因为它是field)
event TestDelegate TestE; // Passed
TestDelegate TestD; // Error: Interfaces cannot contain fields
}

public class Parent {
public event TestDelegate TestE;
public TestDelegate TestD;

protected void RaiseTestE(string s)
{
TestE(s); // The event 'EventAndDelegate.Parent.TestE' can only
// be used from within the type 'EventAndDelegate.Parent'
}
}

public class Child : Parent {
void ChildFunc()
{
// 【区别】 2. event不允许在声明它的class之外(即使是子类)被调用(除此之外只能用于+=或-=),而plain delegate则允许
TestD("OK"); // Passed
TestE("Failure"); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
// the left hand side of += or -= (except when used from within
// the type 'EventAndDelegate.Parent')

// 【补充】 在子类中要触发父类声明的event,通常的做法是在父类中声明一个protected的Raisexxx方法供子类调用
RaiseTestE("OK"); // The class 'EventAndDelegate.Child' can only call the
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event
// 'EventAndDelegate.Parent.TestE'

// 【区别】 同2#
object o1 = TestD.Target;
object o2 = TestE.Target; // The class 'EventAndDelegate.Child' can only call the
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event
// 'EventAndDelegate.Parent.TestE'

// 【区别】 同2#
TestD.DynamicInvoke("OK");
TestE.DynamicInvoke("OK"); // The class 'EventAndDelegate.Child' can only call the
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event
// 'EventAndDelegate.Parent.TestE'
}
}

class Other
{
static void Main(string[] args)
{
Parent p = new Parent();

p.TestD += new TestDelegate(p_Test1); // Passed
p.TestE += new TestDelegate(p_Test1); // Passed

// 【区别】 3. event不允许使用赋值运算符,而plain delegate则允许。
// 注意,对plain delegate,使用赋值运算符意味着进行了一次替换操作!
p.TestD = new TestDelegate(p_Test2); // Passed
p.TestE = new TestDelegate(p_Test2); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
// the left hand side of += or -= (except when used from within
// the type 'EventAndDelegate.Parent')

// 【区别】 同2#
p.TestD("OK"); // Passed
p.TestE("Failure"); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
// the left hand side of += or -= (except when used from within
// the type 'EventAndDelegate.Parent')
}

static void p_Test1(string s)
{
Console.WriteLine("p_Test1: " + s);
}

static void p_Test2(string s)
{
Console.WriteLine("p_Test2: " + s);
}
}
}

写代码的过程中,经常会在delegate和event之间进行选择,以前也没仔细思考选择的原因,今天终于忍不住花了半天时间仔细琢磨了一下……好了,直接拿代码说话吧:






















































































分析:
- plain delegate与event的关系类似于field与Property(实事上前者就是field,或者我们可以把event看成是一种特殊的Property)
- 正是由于1#,在使用上,plain delegate几乎没有任何限制,而event则有严格的限制(只能用在+=和-=的左边)
结论:
- event更面向对象一些。
- 当我们需要灵活时,直接使用plain delegate;反之,需要严格的控制时,使用event。
- 由于event不能使用赋值运算符,因此有时我们要求一个事件在任何时刻只能有一个响应方法时,我们使用plain delegate更为方便。
- ……(大家补充)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)