前进中的蜗牛

番茄大叔

水滴穿石,非一日之功;没有量变,何来质变。

.Net之美读书笔记3

委托

委托的定义

委托(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
posted @ 2017-12-12 10:27  LoveTomato  阅读(209)  评论(0编辑  收藏  举报