第3章 C#中的委托和事件
3.1 理解委托
3.1.1 将方法作为方法的参数
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使程序具有更好的可扩展性。
使用方式:
1.首先定义两个方法
public void EnglishGreeting(string name)
{
Console.WriteLine("Morning, " + name);
}
public void ChineseGreeting(string name)
{
Console.WriteLine("早上好, " + name);
}
2.定义一个委托
public delegate void GreetDelegate(string name);
3.定义一个使用委托的方法
//注意此方法,它接受一个GreetingDelegate类型的方法作为参数
public static void GreetPeople(string name, GreetDelegate MakeGreeting)
{
MakeGreeting(name);
}
4.使用委托方法
static void Main(string[] args)
{
GreetPeople("zzh",EnglishGreeting);
GreetPeople("中华",ChineseGreeting);
Console.ReadLine();
}
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使程序具有更好的可扩展性。
第二种使用委托的方式:
第三种方式,绕过GreetPeople方法(比较喜欢这种方法)
既然委托可以绑定一个方法,那么也应该有办法取消对方法的绑定,很容易想到,这个语法是“-=”。
3.2 事件的由来
使用事件不仅能获得比委托更好的封装性,还能限制含有事件的类型的能力。
1.首先,准备两个方法:
public static void EnglishGreeting(string name)
{
Console.WriteLine("Morning, " + name);
}
public static void ChineseGreeting(string name)
{
Console.WriteLine("早上好, " + name);
}
2.然后呢,准备一个一个委托类型
//定义委托,它定义了可以代表的方法的类型
public delegate void GreetingDelegate(string name);
3.接着准备一个事件,来使用这个委托类型(此处放在一个GreepManager类中)
public class GreetingManager
{
//声明事件
public event GreetingDelegate MakeGreet;
public void GreetPeople(string name)
{
MakeGreet(name);
}
}
4.最后使用这个事件方法
static void Main(string[] args)
{
GreetingManager gm = new GreetingManager();
gm.MakeGreet += EnglishGreeting;//注意此处,并没用使用先赋值的方式
gm.MakeGreet += ChineseGreeting;
gm.GreetPeople("zzh");
}
3.2.2 限制类型能力
使用事件不仅能获得比委托更好的封装性,还能限制含有事件的类型的能力。这是什么意思呢?它的意思是说:事件应该由事件的发布者触发,而不应该由事件的客户端(客户程序)来触发。
1.首先定义一个委托
// 定义委托
public delegate void NumberChangedEventHandler(int count);
2.然后呢,定义一个事件发布者
// 定义事件发布者
public class Publishser
{
private int count;
public NumberChangedEventHandler NumberChanged; // 声明委托变量
public void DoSomething()
{
// 在这里完成一些工作 ...
if (NumberChanged != null)
{ // 触发事件
count++;
NumberChanged(count);
}
}
}
3.接着定义一个事件接收者
// 定义事件订阅者
public class Subscriber
{
public void OnNumberChanged(int count)
{
Console.WriteLine("Subscriber notified: count = {0}", count);
}
}
4.最后就是使用事件了
class Program
{
static void Main(string[] args)
{
Publishser pub = new Publishser();
Subscriber sub = new Subscriber();
pub.NumberChanged += new NumberChangedEventHandler(sub.OnNumberChanged);
pub.DoSomething(); // 应该通过DoSomething()来触发事件
pub.NumberChanged(100); // 也可以被这样直接调用,对委托变量的不恰当使用
Console.ReadLine();
}
}
理解:首先声明发布者和接收者,然后为发布者里的委托变量赋值,调用订阅者的方法,使用发布者里面的方法,启动事件的发生,然后……有点绕,再看看吧……
这里还有一个约定俗称的规定,就是订阅事件的方法的命名,通常为“On事件名”,比如这里的OnNumberChanged。
3.4 .NET框架中的委托和事件
假设有个高档的热水器,当水温超过95度的时候:一、扬声器会开始发出语音,告诉你水的温度;二、液晶屏也会改变水温的显示,以提示水已经快烧开了。现在需要写个程序来模拟这个烧水的过程,我们将定义一个类来代表热水器,将它取名为Heater,它有代表水温的字段temperature,当然,还有必不可少的水加热方法BoilWater(),一个发出语音警报的方法MakeAlert(),一个显示水温的方法,ShowMsg()。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestEventAndDelegate
{
public class Heater
{
private int temperature; // 水温
// 烧水
public void BoilWater()
{
for (int i = 0; i <= 100; i++)
{
temperature = i;
if (temperature > 95)
{
MakeAlert(temperature);
ShowMsg(temperature);
}
}
}
// 发出语音警报
private void MakeAlert(int param)
{
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
// 显示水温
private void ShowMsg(int param)
{
Console.WriteLine("Display:水快开了,当前温度:{0}度。", param);
}
}
class Program
{
static void Main()
{
Heater ht = new Heater();
ht.BoilWater();
Console.ReadLine();
}
}
}
3.4.3 实现示例的Observer设计模式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestEventAndDelegate
{
// 热水器
public class 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 > 95)
{
if (BoilEvent != null)
{ //如果有对象注册
BoilEvent(temperature); //调用所有注册对象的方法
}
}
}
}
}
// 警报器
public class Alarm
{
public void MakeAlert(int param)
{
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
}
// 显示器
public class Display
{
public static void ShowMsg(int param)
{ //静态方法
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
}
}
class Program
{
static void Main()
{
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.BoilEvent += alarm.MakeAlert; //注册方法
heater.BoilEvent += (new Alarm()).MakeAlert; //为匿名对象注册方法
heater.BoilEvent += Display.ShowMsg; //注册静态方法
heater.BoilWater();//烧水,会自动调用注册过对象的方法
Console.ReadLine();
}
}
}
网友评论