C#学习笔记--委托与事件(读自C#从入门到精通 第2版)

委托

委托也叫代理,即把事情交给别人代办。C#中如果将一个方法委托给一个对象,对象即可全权代理该方法的执行。使用委托时首先要定义委托,声明委托所能代理方法的类型。

// 语法
<访问修饰符> delegate 返回类型 委托名();

委托没有具体的实现体,委托能够代表什么样的方法由它的返回值类型和参数列表决定。

// 示例
public delegate void testDelegate(string name);

定义了上述委托示例之后要使用委托,首先要实例化委托,也就是将其指向某个方法,即调用委托的构造函数,并将相关联的方法作为参数传递。然后通过调用 委托,执行相关方法的代码,实现委托。

// 使用委托对数组进行降序排列
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelegateSort
{
    class Program
    {
        public delegate bool SortDelegate(int[] x); // 定义委托SortDelegate
        static void Main(string[] args)
        {
            int[] arr = new int[] { 8, 9, 5, 3, 4, 6, 1 };
            Console.WriteLine("排序前的数组是: ");
            foreach (int i in arr) Console.Write("{0}", i); // 8953461
            SortDelegate myDelegate; // 声明委托变量
            myDelegate = new SortDelegate(Test.SortArray); // 实例化委托变量,委托Test的SortArray
            myDelegate(arr); // 传递参数,调用委托排序
            Console.WriteLine("");
            Console.WriteLine("排序后的数组是:");
            foreach (int i in arr) Console.Write("{0}", i); // 9865431
            Console.ReadKey();
        }
    }

    class Test
    {
        public static bool SortArray(int[] array )
        {
            // 定义方法SortArray用于按照降序排序
            // GetUpperBound(int dimension): 获取数组中指定维度最后一个元素的索引。 dimension Int32 数组的从零开始的维度,其上限需要确定。
            for (int i = array.GetUpperBound(0); i >= 0; i--) // 循环从后向前取出数组的元素
            {
                // 冒泡排序,将数值小的元素移到后面,直到所有的元素按照降序排列
                for(int j = 0; j <= i; j++)
                {
                    if(array[j] <= array[i]) // 判断数组前面的值是否小于后面的值
                    {
                        Swap(ref array[j], ref array[i]); // 交换二者的位置
                    }
                }
            }
            return true; // 并非所有代码都有返回值,故加return true
        }
        static void Swap(ref int x, ref int y) // 交换方法
        {
            int temp = y;
            y = x;
            x = temp;
        }
    }
}
事件

事件是C#中的一个高级概念,是操作发生时允许执行特定应用程序的代码的机制。事件要么在相关联的操作发生前发生(事前事件),要么在操作发生后发生(事后事件)。例如,当用户单击窗口中的按钮时,将引发一个事后事件,以允许执行特定于应用程序的方法。

类或对象可以通过事件向其他类或对象通知发生的相关事情。发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。在典型的C# Windows窗体或Web应用程序中,可以订阅由控件(如按钮和列表框)引发的事件。

定义和使用事件的步骤:
(1) 在一个类中声明关于事件的委托。

public delegate void 事件类型名称(object serder, EventArgs e); 

事件类型名称建议用EventHandler结尾。如果想自定义事件的参数EventArgs,可以用EventArgs类派生自己的事件参数类,也可以没有参数。
(2)在类中声明事件,使用步骤(1)的delegate作为事件的类型。

public event 事件类型名称 事件名称;

(3)在类中需要引发事件的方法中,编写引发事件的方法。

事件名称(this, new EventArgs());
// 或者
if(事件名称 != null) 事件名称 (this, new EventArgs());

(4)订阅事件,当事件发生时通知订户。

带有事件的类实例.事件名称 += new 事件名称(事件处理方法名称);

(5)编写事件处理方法。

public void 事件处理方法(object sender, EventArgs e)
{
	// 相关代码
}

(6)在适当的条件下触发事件,即需要调用步骤(3)中的引发事件的方法。

事件的定义和使用示例
假设设计一个高档热水器,通电加热到水温超过96℃的时候,扬声器会发出语音告诉你水的温度,液晶屏显示水温的变化,提示水快烧开了。定义一个类来代表热水器的类Heater,它有代表水温的字段temperature,有给水加热的BoilWater()方法,发出语音警报的MakeAlert()方法,显示水温的ShowMsg()方法。

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

namespace HeaterEvent
{
    class Program
    {
        static void Main(string[] args)
        {
            Heater heater = new Heater(); // 创建热水器对象heater
            Alarm alarm = new Alarm(); // 创建报警器对象alarm
            heater.BoilEvent += alarm.MakeAlert; // 给alarm的MakeAlert方法订阅事件
            heater.BoilEvent += Display.ShowMsg; // 订阅静态方法
            heater.BoilWater(); // 烧水,会自动调用订阅过的对象方法
            Console.ReadKey();
            /**
             * Alarm: 嘀嘀嘀,水已经97度了!
             * Display:水快烧开了,当前温度:97度。
             * Alarm: 嘀嘀嘀,水已经98度了!
             * Display:水快烧开了,当前温度:98度。
             * Alarm: 嘀嘀嘀,水已经99度了!
             * Display:水快烧开了,当前温度:99度。
             * Alarm: 嘀嘀嘀,水已经100度了!
             * Display:水快烧开了,当前温度:100度。
             */
        }
    }
    public class Heater // 热水器类Heater
    {
        private int temperature; // 声明表示水温的字段
        public delegate void BoilHandler(int param); // 声明关于事件的委托
        public event BoilHandler BoilEvent; // 声明水要烧开的事件
        public void BoilWater() // 烧水的方法
        {
            for(int i = 0; i <= 100; i++) // 循环表示水温的变化
            {
                temperature = i; // 设置水的温度
                if(temperature > 96) // 水温超过96度,引发事件BoilEvent
                {
                    /*if(BoilEvent != null)
                    {
                        // 如果有对象订阅
                        BoilEvent(temperature); // 调用所有订阅对象的方法
                    }*/
                    // 优化
                    BoilEvent?.Invoke(temperature); // 如果有对象订阅,调用所有订阅对象的方法
                }
            }
        }
    }

    public class Alarm // 定义报警类
    {
        public void MakeAlert(int param) // 水快开时报警的方法
        {
            Console.WriteLine("Alarm: 嘀嘀嘀,水已经{0}度了!", param);
        }
    }

    public class Display // 显示水温的显示类
    {
        // 静态方法 ShowMsg用于显示水温
        public static void ShowMsg(int param)
        {
            Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值