惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - MHL

SSRS 2016 Forms Authentication 存储配置关系&知识图谱 Neo4j 使用cypher语言进行查询 项目实战--知识图谱初探 - MHL - 博客园 .NET Core多语言 ASP.NET Core WebApi 返回统一格式参数 C#启动外部程序以及等待外部程序关闭的几种方法 开源.net 混淆器ConfuserEx介绍 CRUD Operations In ASP.NET MVC 5 Using ADO.NET asp.net mvc 利用过滤器进行网站Meta设置 【译】RAID的概念和RAID对于SQL性能的影响 【转】Sql server锁,独占锁,共享锁,更新锁,乐观锁,悲观锁 One Day WinForm简单进度条 金庸群侠传 3小时爆机 ExtJs Set PropertyGrid Column Name ExtJs GridPanel 生成列 电脑上玩 Google纵横 Microsoft Visual Studio 2010 宣传短片
C#:类的成员--事件
MHL · 2021-08-31 · via 博客园 - MHL

鸿门宴上项羽摔杯为号,埋伏两侧的刀斧手就会杀将而来,将刘邦一干人等就地伏法。这就是一个事件模型。

事件模型:事件拥有者、事件、事件响应者、响应事件的处理方法、事件订阅;当某种情况发生时,触发事件。

  • 以鸿门宴摔杯为号的故事为例:
    1. 事件拥有者:项羽
    2. 事件:摔杯子
    3. 事件参数(重要但非必须):谁摔了杯子(对于杀手来说,管你3721,听过杯子摔了就是干。)
    4. 事件响应者:刀斧手
    5. 事件订阅:项羽对刀斧手说:“明日设宴,孤以摔杯为号,尔等即刻行事!”
    6. 事件触发:项羽看劝降不成,勃然大怒,抓起杯子摔倒地上。(事件发生是需要触发的,否则事件永远不会发生,事件响应方法也永远不会执行。)

下面通过自定义事件,来模拟摔杯为号的事件模型:

声明事件的第一种方式

class Program
{
    static void Main(string[] args)
    {
        XiangYu zhugong = new XiangYu();
        ShaShou daofushou = new DaoFuShou();
        ShaShou gongjianshou = new GongjianShou();

        //6 杀手订阅主公的摔杯事件
        zhugong.ShuaiBeiziEvent += new EventHandler<BeiziEventArgs>(daofushou.Action);
        zhugong.ShuaiBeiziEvent += gongjianshou.Action;

        //7 触发事件--- 谈判中(项羽可能随时会摔杯子)
        zhugong.Quanxiang();

        Console.ReadKey();
    }
}

//1 事件携带的附加信息
class BeiziEventArgs : EventArgs
{
    //杯子材质
    public string Metarials { get; set; }

    public BeiziEventArgs(string meterials)
    {
        this.Metarials = meterials;
    }
}

//2 定义事件拥有者
class XiangYu
{
    private EventHandler<BeiziEventArgs> eventHandler;

    //3 定义摔杯事件
    public event EventHandler<BeiziEventArgs> ShuaiBeiziEvent
    {
        add
        {
            eventHandler += value;
        }

        remove
        {
            eventHandler -= value;
        }
    }

    public void Quanxiang()
    {
        var ss = "你可以按下s来触发摔杯事件";
        Console.WriteLine(ss);
        do
        {
            Console.WriteLine("宴会进行中...");
            ss = Console.ReadLine();
        } while ("s"!=ss);
        Console.WriteLine("项羽怒了 抄起酒杯摔了下去");
        if (this.eventHandler!=null)
        {
            BeiziEventArgs attachinfo = new BeiziEventArgs("葡萄美酒夜光杯");
            eventHandler.Invoke(this, attachinfo);
        }
    }
}

//4 定义事件响应者
abstract class ShaShou
{
    //5 在响应者中 定义事件处理方法
    public abstract void Action(object sender, BeiziEventArgs e);
}

class DaoFuShou : ShaShou
{
    //刀斧手
    public override void Action(object sender, BeiziEventArgs e)
    {
        Console.WriteLine($"{e.Metarials}被摔了,进去拿人");
    }
}

class GongjianShou : ShaShou
{
    //弓箭手
    public override void Action(object sender, BeiziEventArgs e)
    {
        Console.WriteLine($"{e.Metarials}被摔了,准备放箭");
    }
}

运行结果:
摔杯事件
代码分析:

  • 这是一个标准的 事件位于事件拥有者中、事件处理方法位于事件响应者中的实现方式:
    简略关系
  • 从事件的声明方式上可以看出,事件是类的一个成员;不要把事件误认为是一种类型;
  • 第六步订阅事件的时候,可以使用委托实例、也可以使用方法名,这是一个语法糖;

声明事件的第二种方式:使用事件声明语法糖,来完成上面的功能,在XiangYu类型改动如下:

class XiangYu
{
    //3 定义摔杯事件
    public event EventHandler<BeiziEventArgs> ShuaiBeiziEvent;

    public void Quanxiang()
    {
        var ss = "你可以按下s来触发摔杯事件";
        Console.WriteLine(ss);
        do
        {
            Console.WriteLine("宴会进行中...");
            ss = Console.ReadLine();
        } while ("s"!=ss);
        Console.WriteLine("项羽怒了 抄起酒杯摔了下去");
        if (this.ShuaiBeiziEvent!=null)
        {
            BeiziEventArgs attachinfo = new BeiziEventArgs("葡萄美酒夜光杯");
            ShuaiBeiziEvent.Invoke(this, attachinfo);
        }
    }
}

为什么说 public event EventHandler ShuaiBeiziEvent; 是一种语法糖,我们通过反编译工具可以看出:编译器看到这句代码时,为我们声明了一个私有的委托字段、一个add_xxx方法追加一个委托、一个remove_xxx方法移除一个委托
事件语法糖
其实从反编译出来的代码可以看出,这两个方法的详细实现:
add
remove
分析以上内容后我们发现,事件声明语法糖,是编译器以一种安全的方式为我们隐去了第一种方式的步骤,所以我们推荐第二种方式,但要知其然知其所以然;另外,事件是委托的包装器。他包装的这个委托内部维护了一个委托链。
内部实现

下面是"摔杯为号"故事的详细关系图:

详细实现
本篇中并没有定义一种新的委托类型,而是使用了.NET为我们提供的EventHanler委托类型,为的是不做额外的工作(也不建议无脑定义委托类型,因为.NET为我们提供的委托类型大部分都够用了);若真的需要定义一种委托类型来约束事件处理方法的话,委托类型名要以EventHadnler结尾,如:ClickEventHandler;事件模式更多是用于客户端程序中的,因为他们是基于事件驱动的;事件用的多,而自己定义的情况很少,但是在我们使用事件前了解清楚事件的原理是十分重要的。

如本文的标题一样:事件是类的成员;类的三大成员:属性、方法、事件。以上便是对事件的总结,记录下来以便以后查阅。