委托事件

1.概念

委托:一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。你可以通过委托实例调用方法。委托用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用的方法。

事件:类或对象可以通过事件向其他类或对象通知发生的相关事情。发送(或引发)事件的类称为“发布者”,接收(或处理)事件的类称为“订阅者”。

2.示例

2.1水壶烧水事件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace task3
{
    public delegate void MyAlarm(int temperature);           //创建委托报警
    public delegate void MyDispaly(int temperature);         //创建委托显示
    class Heater             //热水器类
    {
        private int temperature;    //温度
        public int Temperature
        {
            get { return temperature; }
            set
            {
                if ((temperature >= 0) && (temperature <= 100))
                    temperature = value;
                else
                    Console.WriteLine("温度有问题!显示出错!");
            }
        }
        public event MyAlarm DoMyAlarm;        //建立事件报警
        public event MyDispaly DoMyDisplay;     //建立事件显示
        public void BoilWater(int m)       //m 表示烧水时间,没分钟提高摄氏度
        {
            Console.WriteLine("感谢您使用热水器,现在温度为{0},\n本次烧水时间为{1}分钟。" +
                "(每分钟提高10摄氏度)", this.temperature, m);
            this.temperature = m * 10 + this.temperature;
            if (this.temperature >= 100)
                this.temperature = 100;
            if (this.temperature >= 95)
            {
                DoMyAlarm(this.temperature);
                DoMyDisplay(this.temperature);
                Console.WriteLine("");
            }
            else
                Console.WriteLine("目前还没烧开!\n");
        }
    }
 
    class Alarm            //报警器类
    {
        public void MakeAlert(int temperature)
        {
            Console.WriteLine("叮叮叮,叮叮叮。。。\n报警器提示水壶水温现在是{0}",temperature);
        }
    }
    class Display       //显示器类
    {
        public void ShowMsg(int temperature)
        {
            Console.WriteLine("显示器提示现在的水温为{0}", temperature);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Heater he1 = new Heater();     //第一次烧水(水伟烧开,不会触发事件)
            he1.Temperature = 10;
            Alarm al1 = new Alarm();
            Display di1 = new Display();
            he1.DoMyAlarm += al1.MakeAlert;      //建立关联
            he1.DoMyDisplay += di1.ShowMsg;      //建立关联
            he1.BoilWater(1);
 
            Heater he2 = new Heater();     //第二次烧水(水烧开,触发显示与报警事件)
            he2.Temperature = 10;
            Alarm al2 = new Alarm();
            Display di2 = new Display(); 
            he2.DoMyAlarm += al2.MakeAlert;   //建立关联
            he2.DoMyDisplay += di2.ShowMsg;   //建立关联
            he2.BoilWater(10);
 
            Console.Read();
        }
    }
}

 

2.2 情景二

首领A要搞一场鸿门宴,吩咐部下B和C各自带队埋伏在屏风两侧,约定以杯为令:若左手举杯,则B带队杀出;若右手举杯,则C带队杀出;若直接摔杯,则B和C同时杀出。B和C袭击的具体方法,首领A并不关心;

首领A类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace demo
{
    /// <summary>
    /// 首领举杯委托
    /// </summary>
    /// <param name="hand">手:左,右</param>
    public delegate void RaiseEventHandler(string hand);

    /// <summary>
    /// 首领摔杯委托
    /// </summary>
    public delegate void FallEventHandler();

    /// <summary>
    /// 首领A
    /// </summary>
    public class A
    {
        /// <summary>
          /// 首领A举杯事件
          /// </summary>
          public event RaiseEventHandler RaiseEvent;
          /// <summary>
          /// 首领A摔杯事件
          /// </summary>
          public event FallEventHandler FallEvent;

        /// <summary>
        /// 举杯
        /// </summary>
        /// <param name="hand">手:左、右</param>
        public void Raise(string hand)
        {
            Console.WriteLine("首领A{0}手举杯", hand);
            // 调用举杯事件,传入左或右手作为参数
            if (RaiseEvent != null)
            {
                RaiseEvent(hand);
            }
        }
/// <summary> /// 摔杯 /// </summary> public void Fall() { Console.WriteLine("首领A摔杯"); // 调用摔杯事件 if (FallEvent != null) { FallEvent(); } } } }

首领A的类有举杯和摔杯两种方法,其中,举杯方法带有一个形参,用于传递是左手举杯,还是右手举杯。部下B和C的类,各自有一种攻击方法。

 

部下B类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace demo
{
    public class B
    {
        A a;

        public B(A a)
        {
            this.a = a;
            a.RaiseEvent += new RaiseEventHandler(a_RaiseEvent); // 订阅举杯事件
            a.FallEvent += new FallEventHandler(a_FallEvent); // 订阅摔杯事件
        }
        /// <summary>
        /// 首领举杯时的动作
        /// </summary>
        /// <param name="hand">若首领A左手举杯,则B攻击</param>
        void a_RaiseEvent(string hand)
        {
            if (hand.Equals(""))
            {
                Attack();
            }
        }

        /// <summary>
        /// 首领摔杯时的动作
        /// </summary>
        void a_FallEvent()
        {
            Attack();
        }

        /// <summary>
        /// 攻击
        /// </summary>
        public void Attack()
        {
            Console.WriteLine("部下B发起攻击,大喊:猛人张飞来也!");

        }
    }
}

部下C类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace demo
{
    public class C
    {

        A a;
        public C(A a)
        {
            this.a = a;
            a.RaiseEvent += new RaiseEventHandler(a_RaiseEvent); // 订阅举杯事件
            a.FallEvent += new FallEventHandler(a_FallEvent); // 订阅摔杯事件
        }

        /// <summary>
        /// 首领举杯时的动作
        /// </summary>
        /// <param name="hand">若首领A右手举杯,则攻击</param>
        void a_RaiseEvent(string hand)
        {
            if (hand.Equals(""))
            {
                Attack();
            }
        }

        /// <summary>
        /// 首领摔杯时的动作
        /// </summary>
        void a_FallEvent()
        {
            Attack();
        }

        /// <summary>
        /// 攻击
        /// </summary>
        public void Attack()
        {
            Console.WriteLine("部下C发起攻击,一套落英神掌打得虎虎生威~");
        }
    }
}

我们需要在首领A类中,采用一种方法,把其意图传递出去。在首领A类之前,分别定义一个带形参的举杯委托RaiseEventHandler和一个不带形参的摔杯委托FallEventHandler。

在部下B和C心中,必须存在首领A,才能执行A的暗示吧。所以,在B类和C类中,需要声明一个A,该声明可以通过B和C的构造函数进行实例化。实例化之后,便可在类B和类C中订阅类A的事件了。

using System;

namespace demo
{
    class Program
    {

        static void Main(string[] args)
        {
            A a = new A(); // 定义首领A

            B b = new B(a); // 定义部下B

            C c = new C(a); // 定义部下C

            // 首领A左手举杯
            a.Raise("");

            // 首领A右手举杯
            //a.Raise("右");

            // 首领A摔杯
            //a.Fall();

            Console.ReadLine();
            // 由于B和C订阅了A的事件,所以无需任何代码,B和C均会按照约定进行动作。
        }
    }
}

 

posted @ 2022-03-09 16:53  答辉  阅读(245)  评论(0)    收藏  举报