委托
委托的定义
委托(delegate)可以理解为函数类型,实现了函数可以当作参数传递,使程序更加灵活。下面通过代码快速熟悉委托的使用顺序。
//1. 声明委托类型
public delegate void GreetingDelegate(string name);
class Program
{
//2.定义委托方法体
public static void EnglishGreeting(string name)
{
Console.WriteLine("Morning," + name);
}
public static void ChineseGreeting(string name)
{
Console.WriteLine("早上好," + name);
}
public static void GreetPeople(string name, GreetingDelegate markGreet)
{
//4.调用委托
markGreet(name);
}
static void Main(string[] args)
{
//3.将函数赋值给委托
GreetPeople("Jerry Zhao", EnglishGreeting);
GreetPeople("番茄赵", ChineseGreeting);
Console.ReadKey();
}
事件
事件(event):对委托的封装,保护委托不允许外部程序直接为委托赋值(会将已添加的委托丢掉)。
使用方法public event GreetingDelegate MarkGreet;
.Net事件模型
这里借助一个熟悉的例子讲诉事件模型。热水器烧水到95后,报警器报警,显示器显示。
/// <summary>
/// 加热器
/// </summary>
public class Heater
{
private int temperature;
/// <summary>
/// 型号
/// </summary>
public string type = "RealFire 001";
/// <summary>
/// 产地
/// </summary>
public string area = "China Xian";
/// <summary>
/// 委托
/// </summary>
/// <param name="sender">被观察者(Heater)</param>
/// <param name="e">传递到观察者的参数</param>
public delegate void BoiledEnentHandler(object sender, BoiledEventArgs e);
/// <summary>
/// 初始化空函数,防止没有订阅值为null,调用报错
/// </summary>
public event BoiledEnentHandler Boiled = (sender, e) => { };
/// <summary>
/// 注意这里使用内部类,只是传递参数
/// 被观察着传入到观察者参数
/// </summary>
public class BoiledEventArgs : EventArgs
{
public readonly int temperature;
public BoiledEventArgs(int temperature)
{
this.temperature = temperature;
}
}
/// <summary>
/// 被观察者通知观察者方法
/// </summary>
/// <param name="e">参数</param>
protected virtual void OnBoiled(BoiledEventArgs e)
{
//#1多播委托
/*
foreach(Delegate d in Boiled.GetInvocationList())
{
BoiledEnentHandler boiled = (BoiledEnentHandler)d;
boiled(this, e);
}
*/
//#2异常处理,一个主题有多个订阅者。订阅者一个订阅者发出异常不应该阻塞其他订阅者
/*
foreach (Delegate d in Boiled.GetInvocationList())
{
BoiledEnentHandler boiled = (BoiledEnentHandler)d;
try
{
boiled(this, e);
}
catch (Exception ex)
{
}
}
*/
//#3超时处理,发布者不应这个通知订阅者,应采用一部调用
foreach (Delegate d in Boiled.GetInvocationList())
{
BoiledEnentHandler boiled = (BoiledEnentHandler)d;
boiled.BeginInvoke(this, e, null, null);
}
//Boiled(this, e);
}
/// <summary>
/// </summary>
public void BoilWater()
{
for (int i = 0; i <= 100; i++)
{
temperature = i;
if (temperature > 95)
{
BoiledEventArgs e = new BoiledEventArgs(temperature);
OnBoiled(e);
}
}
}
}
/// <summary>
/// 报警器
/// </summary>
public class Alarm
{
public void MarkAlert(object sender, Heater.BoiledEventArgs e)
{
Heater heater = (Heater)sender;
Console.WriteLine("Alarm:{0}-{1}", heater.area, heater.type);
Console.WriteLine("Alarm:嘀嘀嘀,水已经{0}度", e.temperature);
Console.WriteLine();
Thread.Sleep(500);
}
}
/// <summary>
/// 显示器
/// </summary>
public class Display
{
public static void ShowMsg(object sender, Heater.BoiledEventArgs e)
{
Heater heater = (Heater)sender;
if (e.temperature == 99)
{
Thread.Sleep(2000);
}
Console.WriteLine("Display:{0}-{1}", heater.area, heater.type);
Console.WriteLine("Display:水已经{0}度", e.temperature);
Console.WriteLine();
}
}
//调用
static void Main(string[] args)
{
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.Boiled += alarm.MarkAlert;
heater.Boiled += Display.ShowMsg;
heater.BoilWater();
Console.ReadKey();
}
委托进阶
利用上面的代码介绍下多播的进阶
- 1多播委托的调用
- 2异常处理,多播中异常处理
- 3超时处理,委托的异步调用成对出现 BeginXXX,EndXXX