14 C# 第十三章 事件和委托(一) 多播委托的问题

来源:互联网 发布:淘宝天猫买药可靠吗 编辑:程序博客网 时间:2024/05/21 23:33

一个简单的概述

这里有一个小小的例子描述了一些单独使用委托链的局限。

知道了使事件的优势,用委托链的不足,也就更清楚了使用这样便于在设计时灵活的选择。


多播委托(委托链)

一个简单的实例:(cooler and heater)

程序中有两个工作实体, Cooler 和 Heater,它们会根据输入的温度改变自己的状态(On 或 Off)  有一个管理者Thermostat,Cooler 和 Heater会注册到它的委托链上。Main直接操纵Thermostat,把温度的输入给它,Thermostat会根据委托链上的委托进行操作。

这个小程序的主要目的是为了解释委托在使用时的不足之处。尤其通过时序图可以看的更加的清楚。


时序图:最有趣的是红色方框部分,当改变温度时委托链中的委托会被顺序的访问。

sequence_diagram

注意红色方框的部分, 有下面几个问题是值得考虑的:


1)  委托链中的异常
这是能想到的最直接的问题。委托链中的委托是被顺序访问的,当其中一个出现了异常,就会打破这个链。例如上面的委托链中 heater 先被访问,然后是cooler。可能cooler是我们需要处理温度变化的对象,但在委托链在访问 heater时出了异常,cooler就无法再执行了,虽然cooler可能一点问题都没有,但它没办法执行。


2)  委托链中的返回值

假设程序需要扩展一下,在第11步和第13步需要返回值给控制端,当控制端收到第11步的返回值后,委托链并没有终止,而是继续了13步,这样最终的返回值将总是第13步的返回值。



3)  委托运算符,关于 “+=”  和  "-=" 操作
+=: 可以像委托队列中增加一个委托,它会取得委托链中的第一个委托,然后向后加入新的委托。在其内部使用的是System.Delegate.Combine()方法.

-+:  会从委托链中删除一个委托,但其实质并不是从委托链中删除一委托,使委托链比原来的少一个,而是建了一个新的委托链,这个新的委托链的基础是把原来的委托链减去目标的委托。其调用的是 System.Delegate.Remove() 方法。这里加了个MSDN的连接。



4)  委托空值的检查
无论是System.Delegate.Combine()还是System.Delegate.Remove()都是允许对空值操作的,在使用委托链时最好也判断一下。


实例程序:(对应上面的时序图)

using System;using System.Collections.Generic;using System.Text;namespace delegate_bad_point{    class Cooler    {        private float m_fTemperature;        public Cooler(float fTemperature)        {            m_fTemperature = fTemperature;        }        public float Temperature        {            get { return m_fTemperature; }            set { m_fTemperature = value;}        }        public void OnTemperatureChaged(float fNewTemperature)        {            if (fNewTemperature > m_fTemperature)            {                Console.WriteLine("Cooler : ON");            }            else            {                Console.WriteLine("Cooler : OFF");            }        }    }    class Heater    {        private float m_fTemperature;        public Heater(float fTemperature)        {            m_fTemperature = fTemperature;        }        public float Temperature        {            get { return m_fTemperature; }            set { m_fTemperature = value; }        }        public void OnTemperatureChaged(float fNewTemperature)        {            if (fNewTemperature < m_fTemperature)            {                Console.WriteLine("Heater : ON");            }            else            {                Console.WriteLine("Heater : OFF");            }        }    }    public class Thermostat    {        public delegate void TemperatureChangedHandler(float newTemperature);        private TemperatureChangedHandler m_OnTemperatureChange;        private float m_fCurrentTemperature;        public TemperatureChangedHandler OnTemperatureChanged        {            get { return m_OnTemperatureChange; }            set { m_OnTemperatureChange = value; }        }        public float CurrentTemperature        {            get { return m_fCurrentTemperature; }            set             {                if (m_fCurrentTemperature != value)                {                    m_fCurrentTemperature = value;                    TemperatureChangedHandler localOnChange = m_OnTemperatureChange;                    // check the null value, it's important                    if (localOnChange != null)                        localOnChange(value);                }            }        }    }    class Program    {        static void Main(string[] args)        {            Cooler cool = new Cooler(80);            Heater heat = new Heater(60);            Thermostat thermostat = new Thermostat();            string strTemp = "";            thermostat.OnTemperatureChanged += heat.OnTemperatureChaged;            thermostat.OnTemperatureChanged += cool.OnTemperatureChaged;            Console.WriteLine("Enter temperature: ");            strTemp = Console.ReadLine();            thermostat.CurrentTemperature = float.Parse(strTemp);            Console.ReadKey();        }    }}


下面将会使用事件方式来解决委托链中的问题。



原创粉丝点击