AI智能
改变未来

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); // 定义委托SortDelegatestatic 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); // 8953461SortDelegate myDelegate; // 声明委托变量myDelegate = new SortDelegate(Test.SortArray); // 实例化委托变量,委托Test的SortArraymyDelegate(arr); // 传递参数,调用委托排序Console.WriteLine(\"\");Console.WriteLine(\"排序后的数组是:\");foreach (int i in arr) Console.Write(\"{0}\", i); // 9865431Console.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(); // 创建热水器对象heaterAlarm alarm = new Alarm(); // 创建报警器对象alarmheater.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);}}}
  • 点赞
  • 收藏
  • 分享
  • 文章举报

Yeats.NeverGiveUp发布了12 篇原创文章 · 获赞 0 · 访问量 161私信关注

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » C#学习笔记–委托与事件(读自C#从入门到精通 第2版)