c#专题——事件

一、多播委托实现观察者模式
多播委托就是一个委托上面绑定多个方法,当调用委托时,多个方法按照一定的顺序执行,本例子以温控器为例,当温度发生变化时,会引起冷却器和加热器的变化。
定义事件的订阅者

class Cooler
    {
        public Cooler(double temperature)
        {
            this.Temperature = temperature;

        }
        public double Temperature { get; set; }


        public void TemperatureChanged(double temperature)
        {
            if (temperature > Temperature)
            {
                Console.WriteLine("当前温度过高,冷却器开启");
            }
            else
            {
                Console.WriteLine("当前温度过低,冷却器关闭");
            }
        }
    }
  class Heater
    {
        public Heater(double temperature)
        {
            this.Temperature = temperature;

        }
        public double Temperature { get; set; }


        public void TemperatureChanged(double temperature)
        {
            if (temperature > Temperature)
            {
                Console.WriteLine("当前温度过高,加热器关闭");
            }
            else
            {
                Console.WriteLine("当前温度过低,加热器开启");
            }
        }
    }

定义事件发布者

  class Thermostat
    {
        public Action<double> temperatureChangeDelegate { get; set; }
        private double _CurrentTemperature;
        public double CurrentTemperature
        {
            get
            {
                return _CurrentTemperature;
            }
            set
            {
                if(value!=CurrentTemperature )
                {
                    _CurrentTemperature = value;
                    Action<double> temperatureChangeDelegateNew = temperatureChangeDelegate;//防止在别的线程将Null赋值为null,从而引发异常
                    if (temperatureChangeDelegateNew!=null)
                    {
                        List<Exception> exceptions = new List<Exception>();//处理异常从而保证委托链不会因为异常导致有些委托链中的方法不执行
                        foreach (Action<double> handler in temperatureChangeDelegate.GetInvocationList() )
                        {
                            try
                            {
                                handler(value);
                            }
                            catch(Exception ex)
                            {
                                exceptions.Add(ex);
                            }
                        }
                        if(exceptions .Count >1)
                        {
                            throw new AggregateException("temperatureChangeDelegateNew有异常",exceptions );
                        }
                    }
                    
                }
            }
        }
    }

调用委托

 Thermostat thermostat = new Thermostat();
            Cooler cooler = new Cooler(80);
            Heater heater = new Heater(30);
            thermostat.temperatureChangeDelegate += cooler.TemperatureChanged;
            thermostat.temperatureChangeDelegate += heater.TemperatureChanged;
            thermostat.CurrentTemperature = 100;
当前温度过高,冷却器开启
当前温度过高,加热器关闭

二、事件的由来,上述的委托有两个问题,如下:
1)在定义委托的类的外部直接可以调用委托,而我们想实现地目的是通过属性来触发委托的执行,而不能直接调用委托;
2)由于委托实例化时可以使用“=”号,有可能在写程序时,写成如下代码,这样就删除了一个方法,如果我们能实现禁止使用“=”号,这样就帮我们解决了问题
thermostat.temperatureChangeDelegate = cooler.TemperatureChanged;
thermostat.temperatureChangeDelegate = heater.TemperatureChanged;
由于事件可以解决如上的问题,所以在使用多播委托的时候,使用事件替代委托是比较好的选择,事件的代码如下:

class Cooler
    {
        public Cooler(TemperatureArgs temperatureArgs)
        {
            this.Temperature = temperatureArgs.NewTemperatere ;

        }
        public double Temperature { get; set; }


        public void TemperatureChanged(object sender, TemperatureArgs e)
        {
            if (e.NewTemperatere > Temperature)
            {
                Console.WriteLine("当前温度过高,冷却器开启");
            }
            else
            {
                Console.WriteLine("当前温度过低,冷却器关闭");
            }
        }
    }
 class Heater
    {
        public Heater(TemperatureArgs temperatureArgs)
        {
            this.Temperature = temperatureArgs.NewTemperatere ;

        }
        public double Temperature { get; set; }


        public void TemperatureChanged(object sender, TemperatureArgs e)
        {
            if (e.NewTemperatere > Temperature)
            {
                Console.WriteLine("当前温度过高,加热器关闭");
            }
            else
            {
                Console.WriteLine("当前温度过低,加热器开启");
            }
        }
    }
 public class TemperatureArgs : System.EventArgs
    {
        public TemperatureArgs(double newTemperature)
        {
            this.NewTemperatere = newTemperature;
        }
        public double NewTemperatere { get; set; }
    }
 class Thermostat
    {
        public event EventHandler<TemperatureArgs> temperatureChangeDelegate = delegate { };//空委托,这样我们就不用在调用事件时先进行null值判断了。


        private double _CurrentTemperature;
        public double CurrentTemperature
        {
            get
            {
                return _CurrentTemperature;
            }
            set
            {
                if (value != CurrentTemperature)
                {
                    _CurrentTemperature = value;
                    temperatureChangeDelegate?.Invoke(this, new TemperatureArgs(CurrentTemperature));
                }
            }
        }
    }

调用:

 Thermostat thermostat = new Thermostat();
    Cooler cooler = new Cooler(new TemperatureArgs (80));
    Heater heater = new Heater(new TemperatureArgs(30));
    thermostat.temperatureChangeDelegate += cooler.TemperatureChanged;
    thermostat.temperatureChangeDelegate += heater.TemperatureChanged;
    thermostat.CurrentTemperature = 100;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c#上位机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值