C# delegate委托 event事件 区别

转载:https://blog.csdn.net/lrfleroy/article/details/88780590

C# delegate委托 和 event事件的区别

理解:

1、区别:
(1)delegate委托event事件不是一个层面的东西,delegate用来声明委托类型,event用来声明委托对象(此时委托对象就是事件)。
(2)事件是委托的一种应用,事件是带有event关键词的委托对象,对委托对象进行了封装,本质就是委托对象。
(3)事件的调用只能在类中,委托无限制。

2、事件Event
(1)    事件对象的定义和委托对象的定义一样,只是多了一个event关键字。从语法上,可以使用event关键字将任意委托对象转化为事件。
(2)    事件event不是一种变量类型,而是类的成员类型,和“字段”、“属性”、“方法”同一层面的东西。(即是类中的字段,类中的方法,类中的事件,这个层面的意思理解。)
(4)    事件的+=、-=操作符可以在类的外部使用,调用事件只能在声明事件的类的内部使用。
(5)    事件的作用
封装订阅: 事件将委托的订阅操作进行封装,仅允许 += 和 -= 操作,避免程序员在开发时因误用 = 使得委托链断裂。
封装发布: 事件确保只有包含它的类(即发布器)才能触发事件通知,杜绝在委托中出现的“订阅者”也能触发的情况。

3、什么时候用委托?什么时候用事件?

出于代码健壮性考虑,如果一个委托不需要在其定义的类之外进行触发,那就将其转化为事件,保证它不会在不可知的情况下被触发。

举例对比:

委托提供与C++中“函数指针”相同的功能,用于传递和调用函数的引用,是观察者模式的一种实现。本篇分别使用委托和事件来实现简单的观察者模式,三个版本输出完全相同,为方便对比,使用了最原始的delegate语法。对比三版的不同之处来了解两者的区别。

委托版本

using System;
 
namespace LearningDelegate
{
    class Program
    {
        static void Main(string[] args)
        {
            //出版社有一本叫《故事会》的杂志
            Publisher publisher = new Publisher("《故事会》");
 
            //读者小A订了这本杂志
            Observer observerA = new Observer("小A");
            publisher.Magazine += observerA.RecieveMagazine;
 
            //读者小B也订了这本杂志
            Observer observerB = new Observer("小B");
            publisher.Magazine += observerB.RecieveMagazine;
 
            //出版社印刷本月的《故事会》
            publisher.PublishingMagazine();
 
            Console.ReadLine();
        }
    }
 
    //读者
    class Observer
    {
        public Observer(string _name)
        {
            name = _name;
        }
        public string name;
 
        public void RecieveMagazine(string message)
        {
            Console.WriteLine("{0}收到了{1}, 仔细阅读了一番。", this.name, message);
        }
    }
 
    //出版社
    class Publisher
    {
        public Publisher(string magName)
        {
            magazineName = magName;
        }
 
        public string magazineName;
 
        public delegate void MagazineDelegate(string message);
        public MagazineDelegate Magazine;
 
        public void PublishingMagazine()
        {
            //如果没人订,就不用印了
            //此处必须判断Delegate对象是否为空,调用空的Delegate对象会引发异常
            if (Magazine != null)
            {
                Magazine(magazineName);
            }
        }
    }
}


委托有一个特点:由于委托的订阅和触发都直接作用于delegate对象,这导致委托可以在可订阅的空间中被触发,也就是说我们无法将委托的触发封装起来。而事件event对象只能在其定义的类中被触发。

 

一个最最简单的事件版本(仅在上段代码上加了event定义事件,其余完全相同)

using System;
 
namespace LearningDelegate
{
    class Program
    {
        static void Main(string[] args)
        {
            //出版社有一本叫《故事会》的杂志
            Publisher publisher = new Publisher("《故事会》");
 
            //读者小A订了这本杂志
            Observer observerA = new Observer("小A");
            publisher.Magazine += observerA.RecieveMagazine;
 
            //读者小B也订了这本杂志
            Observer observerB = new Observer("小B");
            publisher.Magazine += observerB.RecieveMagazine;
 
            //出版社印刷本月的《故事会》
            publisher.PublishingMagazine();
 
            Console.ReadLine();
        }
 
    }
 
    //读者
    class Observer
    {
        public Observer(string _name)
        {
            name = _name;
        }
        public string name;
 
        public void RecieveMagazine(string message)
        {
            Console.WriteLine("{0}收到了{1}, 仔细阅读了一番。", this.name, message);
        }
    }
 
    //出版社
    class Publisher
    {
        public Publisher(string megName)
        {
            magazineName = megName;
        }
 
        public string magazineName;
 
        public delegate void MagazineDelegate(string message);
        //使用自定义的委托类型和event关键字创建事件对象
        public event MagazineDelegate Magazine;
 
        public void PublishingMagazine()
        {
            //如果没人订,就不用印了
            //此处必须判断事件对象是否为空
            if (Magazine != null)
            {
                Magazine(magazineName);
            }
        }
    }
}


这个最最简单的事件,就是给原有的委托加了一层event关键字的封装,增加了上述的两个特性。这个简单的例子只能用于了解委托和事件语法的差别,下面给出标准的事件语法的版本。

 

标准的事件版本(不再使用自定义的委托,使用EventHandler<type> 泛型委托来定义事件)

using System;
 
namespace LearningDelegate
{
    class Program
    {
        static void Main(string[] args)
        {
            //出版社有一本叫《故事会》的杂志
            Publisher publisher = new Publisher("《故事会》");
 
            //读者小A订了这本杂志
            Observer observerA = new Observer("小A");
            publisher.Magazine += observerA.RecieveMagazine;
 
            //读者小B也订了这本杂志
            Observer observerB = new Observer("小B");
            publisher.Magazine += observerB.RecieveMagazine;
 
            //出版社印刷本月的《故事会》
            publisher.PublishingMagazine();
 
            Console.ReadLine();
        }
    }
 
    //读者
    class Observer
    {
        public Observer(string _name)
        {
            name = _name;
        }
        public string name;
 
        //接受信息的函数要与Event的格式保持一致,输入一个object对象和Event消息类
        public void RecieveMagazine(object sender, Publisher.MagazineMessage magazineMessage)
        {
            Console.WriteLine("{0}收到了{1}, 仔细阅读了一番。", this.name, magazineMessage.Message);
        }
    }
 
    //出版社
    class Publisher
    {
        //事件传递的消息必须封装到一个类中,该类必须继承EventArgs类
        public class MagazineMessage : EventArgs
        {
            public MagazineMessage(string mes)
            {
                message = mes;
            }
 
            private string message;
 
            public string Message { get => message; set => message = value; }
        }
 
        public Publisher(string megName)
        {
            magazineName = megName;
        }
        public string magazineName;
 
        //定义Event
        public event EventHandler<MagazineMessage> Magazine;
        //EventHandler<MagazineMessage> 的原型是一个泛型委托:delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)
 
 
        //调用Event,Event只能在自己定义类中被触发调用
        public void PublishingMagazine()
        {
            //与Delegate一样,此处必须判断event对象是否为空,调用空的Event/Delegate对象会引发异常
            if (Magazine != null)
            {
                Magazine(this, new MagazineMessage(magazineName));
            }
        }
    }
}

更为深层的关于委托和事件的理解,请看下列参考资料。

参考资料:

《C#本质论》
C# 事件浅析
大白话系列之C#委托与事件讲解系列

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自动控制节水灌溉技术的高低代表着农业现代化的发展状况,灌溉系统自动化水平较低是制约我国高效农业发展的主要原因。本文就此问题研究了单片机控制的滴灌节水灌溉系统,该系统可对不同土壤的湿度进行监控,并按照作物对土壤湿度的要求进行适时、适量灌水,其核心是单片机和PC机构成的控制部分,主要对土壤湿度与灌水量之间的关系、灌溉控制技术及设备系统的硬件、软件编程各个部分进行了深入的研究。 单片机控制部分采用上下位机的形式。下位机硬件部分选用AT89C51单片机为核心,主要由土壤湿度传感器,信号处理电路,显示电路,输出控制电路,故障报警电路等组成,软件选用汇编语言编程。上位机选用586型以上PC机,通过MAX232芯片实现同下位机的电平转换功能,上下位机之间通过串行通信方式进行数据的双向传输,软件选用VB高级编程语言以建立友好的人机界面。系统主要具有以下功能:可在PC机提供的人机对话界面上设置作物要求的土壤湿度相关参数;单片机可将土壤湿度传感器检测到的土壤湿度模拟量转换成数字量,显示于LED显示器上,同时单片机可采用串行通信方式将此湿度值传输到PC机上;PC机通过其内设程序计算出所需的灌水量和灌水时间,且显示于界面上,并将有关的灌水信息反馈给单片机,若需灌水,则单片机系统启动鸣音报警,发出灌水信号,并经放大驱动设备,开启电磁阀进行倒计时定时灌水,若不需灌水,即PC机上显示的灌水量和灌水时间均为0,系统不进行灌水。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值