认识C#中的委托和事件

本文是学习 博客C# 中的委托和事件(详解) 的心得 ,博客原文为:http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html

委托和事件的用法:

使用委托和事件的目的,在这个例子中,加热器(heater)只负责加热,而报警器(alamter)负责报警和显示器(viewer)负责显示,而加热器如何告诉报警器和显示器?这就需要用到委托(事件)。

使用到了观察者模式

为什么委托定义的返回值通常都为 void ?

尽管并非必需,但是我们发现很多的委托定义返回值都为 void,为什么呢?这是因为委托变量可以供多个订阅者注册,如果定义了返回值,那么多个订阅者的方法都会向发布者返回数值,结果就是后面一个返回的方法值将前面的返回值覆盖掉了,因此,实际上只能获得最后一个方法调用的返回值。可以运行下面的代码测试一下。除此以外,发布者和订阅者是松耦合的,发布者根本不关心谁订阅了它的事件、为什么要订阅,更别说订阅者的返回值了,所以返回订阅者的方法返回值大多数情况下根本没有必要

using System;

//编码规范
//1. 委托类型的名称都应该以 EventHandler 结束。
//2. 委托的原型定义:有一个void 返回值,
//并接受两个输入参数:一个Object 类型,一个EventArgs 类型(或继承自EventArgs)。
//3. 事件的命名为委托去掉 EventHandler 之后剩余的部分。
//4. 继承自 EventArgs 的类型应该以EventArgs 结尾。
namespace testEvent
{
    class MainClass
    {
        public static void Main1 (string[] args)
        {
            Heater heater = new Heater ();
            Alamter a = new Alamter ();
            heater.sendTempure -= a.OnAlam;
            heater.sendTempure += a.OnAlam;
            heater.sendTempure += new Viewer ().OnView;
            heater.boillWater ();
        }
    }
    //监视对象,里面含有被监视的内容:温度
    public class Heater{
        public String Name {
            get;
            set;
        }
        public int Tempurea {
            get;
            set;
        }
        //定义成void,是为了避免多个事件注册而返回值被覆盖,
        //如果有这种需求,可以用特殊方法来避免被多次注册。
        //Object sender 用于监视者强转成监视对象,获取到监视对象的属性,如Name。
        //
        public delegate void sendTempureEventHander (Object sender,BoilEventArgs e);
        public event sendTempureEventHander sendTempure;
        //这个地方必须是空的,因为真正执行任务的是Alamter和Viewer这两个监视者类,
        //而监视对象只是用这个handler来占位而已    
        //要真正使sendTempure内容不为空,需要在真正使用时,绑定监视者的具体方法。
        public void boillWater(){
            for(int i=0;i<100;i++){
                Console.WriteLine ("开始烧水");
                if(i>90){
                    BoilEventArgs boilEventArgs = new BoilEventArgs (i);
                    sendTempure (this, boilEventArgs);
                }
            }
        }
    }
    //承自 EventArgs 的类型应该以EventArgs 结尾。
    public class BoilEventArgs:EventArgs {
        public int Tempure {
            get;
            set;
        }
        public BoilEventArgs(int tempure){
            this.Tempure = tempure;
        }
    }
    //监视者
    //用于报警的类 
    public class Alamter{
        //这里还有一个约定俗称的规定,就是订阅事件的方法的命名,通常为“On 事件名”,比如这里的OnNumberChanged
        public void OnAlam(Object sender, BoilEventArgs e){
            Console.WriteLine ("名字为"+((Heater)sender).Name+"温度达到了:"+e.Tempure+"警报器开始报警");
        }
        public static void OnAlamt(Object sender, BoilEventArgs e){
            Console.WriteLine ("名字为"+((Heater)sender).Name+"温度达到了:"+e.Tempure+"警报器开始报警");
        }
    }
    //用于显示的类
    public class Viewer{
        public void OnView(Object sender, BoilEventArgs e){
            Console.WriteLine ("名字为"+((Heater)sender).Name+"温度达到了:"+e.Tempure+"显示器开始显示");
        }
    }
}

 

如何让事件只允许一个客户订阅?

using System;
namespace OneEvent
{
    public class OneEventPusher{
        public String Name{ get; set;}
        public delegate void ChangeValueEventHandler(Object sender, ChangeEventArgs e);
        private event ChangeValueEventHandler changeValue;
        public void Register(ChangeValueEventHandler handler){
            changeValue = handler;
        }
        //如果changValue为空,-=操作也不会报错
        public void UnRegister(ChangeValueEventHandler handler){
                changeValue -= handler;
        }
        public void doWork(int i){
            //因为在Register 方法时使用的是=,每次changeValue只会注册一个方法,所以,可能会发生UnRegister时,changeValue为空,故需要判断一下
            if(changeValue!=null){
                ChangeEventArgs args = new ChangeEventArgs (i); 
                changeValue(this,args);
            }
        
        }
    }

    public class ChangeEventArgs:EventArgs{
        public int passValue {
            get;
            set;
        }
        public ChangeEventArgs(int pass_value){
            this.passValue = pass_value;
        }
    }

    public class OneEventWorker1{
        public void OnChange(Object sender,ChangeEventArgs changerArgs){
            Console.WriteLine ("I am worker 1!");
            Console.WriteLine (((OneEventPusher)sender).Name);
            Console.WriteLine (changerArgs.passValue);
        }
    }
    public class OneEventWorker2{
        public void OnChange(Object sender,ChangeEventArgs changerArgs){
            Console.WriteLine ("I am worker 2!");
            Console.WriteLine (((OneEventPusher)sender).Name);
            Console.WriteLine (changerArgs.passValue);
        }
    }

    class MainClass
    {
        public static void Main2 (string[] args)
        {
            OneEventPusher one = new OneEventPusher ();
            one.Name ="Test";
            OneEventWorker1 work1 = new OneEventWorker1 ();
            one.Register (work1.OnChange);
            one.UnRegister (work1.OnChange);
            //one.UnRegister (work2.OnChange);
            one.doWork (1);    
        }
    }
}

如何使用委托异步调用观察者:

using System.Threading;
using System;
using System.Runtime.Remoting.Messaging;
namespace UnSynzDemo{
    public delegate void Count();
    class MainClass
    {
        //同步执行
        public static void Main3 (string[] args)
        {
            Console.WriteLine ("Thread name is ---"+Thread.CurrentThread.Name);
            Count count = new Count (new CountClass ().getCounts);
            count() ;
            Console.WriteLine ("main Class is over");
        }
        //异步执行
        public static void Main (string[] args)
        {
            
            if (Thread.CurrentThread.IsThreadPoolThread) {
                Thread.CurrentThread.Name = "this is ThreadPoolThread";
            } else {
                Thread.CurrentThread.Name = "this is mainThread";
            }
            Console.WriteLine ("Thread name is ---"+Thread.CurrentThread.Name);
            Counter counter = new Counter ();
            counter.doWork ();
            Thread.Sleep (5000);
            Console.WriteLine ("main Thread is over");
        }


    }
    class CountClass{
        public void getCounts(){
            int count = 0;
            if (Thread.CurrentThread.IsThreadPoolThread) {
                Thread.CurrentThread.Name = "this is ThreadPoolThread";
            } else {
                Thread.CurrentThread.Name = "this is mainThread";
            }
            Console.WriteLine ("CountClass Thread Name is "+ Thread.CurrentThread.Name);
            for(int i =0;i<10;i++){
                count += i;
                Thread.Sleep (TimeSpan.FromMilliseconds(300));
            }
            Console.WriteLine (count);
        }
        public int OnCounts(int c){
            if (Thread.CurrentThread.IsThreadPoolThread) {
                Thread.CurrentThread.Name = "this is ThreadPoolThread";
            } else {
                Thread.CurrentThread.Name = "this is mainThread";
            }
            Console.WriteLine ("CountClass Thread Name is "+ Thread.CurrentThread.Name);
            int totolCount = 0;
            for(int i =0;i<c;i++){
                totolCount += i;
            }
            return totolCount;
        }
    }
    //用于执行异步操作的delegate
    public delegate int CountNumEventHandler(int c);
    //系统自带的delegate,用于绑定回调函数的方法,参数为固定的IAsyncResult类型
    //public delegate void AsyncCallback(IAsyncResult ar);
    class Counter{
        public void doWork(){
            Console.WriteLine ("doWork Thread Name is "+ Thread.CurrentThread.Name);
            //调用BeginInvoke前面的参数和delegate的参数一致,
            //而后面两个参数,第一个参数表示回调函数,第二个参数表示传递的参数(两个参数都可以为null值)
            //BeginInvoke的返回值为
            int c = 10;
            string data = "123";
            CountNumEventHandler handler = new CountNumEventHandler (new CountClass().OnCounts);
            AsyncCallback callBack = new AsyncCallback (CounterCallBack);
            //后面两个参数都可以为null值
            //handler.BeginInvoke (c,null,null);
            //delegate 参数为空的情况
            //handler.BeginInvoke(null,null);


            //可以直接获取相应的运行结果和传递的参数
            //IAsyncResult IResult =  handler.BeginInvoke(c,callBack,data);
            //IAsyncResult IResult = handler.BeginInvoke (c,null,data);
            //AsyncResult result = (AsyncResult)IResult;
            //int i  = handler.EndInvoke (result);
            //Console.WriteLine (result.AsyncState);
            //Console.WriteLine (i);
            //Console.WriteLine ("do Working is over");



            //也可以在回调函数中获取相应的运行结果和传递的参数
            IAsyncResult IResult =  handler.BeginInvoke(c,callBack,data);
        
        }
        //回调函数
        public void CounterCallBack(IAsyncResult ar){
            Console.WriteLine ("callBack Thread Name is "+ Thread.CurrentThread.Name);
            //转为AsyncResult,此时就可以获取相应的属性了
            AsyncResult result = (AsyncResult)ar;
            CountNumEventHandler handler = (CountNumEventHandler)result.AsyncDelegate;
            //获取方法的返回值
            int rtn = handler.EndInvoke(result);
            Console.WriteLine ("CallBack return is "+rtn);
            string data = (string)result.AsyncState;
            Console.WriteLine ("CallBack passData is "+data);
            Console.WriteLine (data);
            Console.WriteLine ("CallBack Working is over");
        }
    }
}


最终异步调用的结果如下:


JFM7VX690T型SRAM型现场可编程门阵列技术手册主要介绍的是上海复旦微电子集团股份有限公司(简称复旦微电子)生产的高性能FPGA产品JFM7VX690T。该产品属于JFM7系列,具有现场可编程特性,集成了功能强大且可以灵活配置组合的可编程资源,适用于实现多种功能,如输入输出接口、通用数字逻辑、存储器、数字信号处理时钟管理等。JFM7VX690T型FPGA适用于复杂、高速的数字逻辑电路,广泛应用于通讯、信息处理、工业控制、数据中心、仪表测量、医疗仪器、人工智能、自动驾驶等领域。 产品特点包括: 1. 可配置逻辑资源(CLB),使用LUT6结构。 2. 包含CLB模块,可用于实现常规数字逻辑分布式RAM。 3. 含有I/O、BlockRAM、DSP、MMCM、GTH等可编程模块。 4. 提供不同的封装规格工作温度范围的产品,便于满足不同的使用环境。 JFM7VX690T产品系列中,有多种型号可供选择。例如: - JFM7VX690T80采用FCBGA1927封装,尺寸为45x45mm,使用锡银焊球,工作温度范围为-40°C到+100°C。 - JFM7VX690T80-AS同样采用FCBGA1927封装,但工作温度范围更广,为-55°C到+125°C,同样使用锡银焊球。 - JFM7VX690T80-N采用FCBGA1927封装铅锡焊球,工作温度范围与JFM7VX690T80-AS相同。 - JFM7VX690T36的封装规格为FCBGA1761,尺寸为42.5x42.5mm,使用锡银焊球,工作温度范围为-40°C到+100°C。 - JFM7VX690T36-AS使用锡银焊球,工作温度范围为-55°C到+125°C。 - JFM7VX690T36-N使用铅锡焊球,工作温度范围与JFM7VX690T36-AS相同。 技术手册中还包含了一系列详细的技术参数,包括极限参数、推荐工作条件、电特性参数、ESD等级、MSL等级、重量等。在产品参数章节中,还特别强调了封装类型,包括外形图尺寸、引出端定义等。引出端定义是指对FPGA芯片上的各个引脚的功能接线规则进行说明,这对于FPGA的正确应用电路设计至关重要。 应用指南章节涉及了FPGA在不同应用场景下的推荐使用方法。其中差异说明部分可能涉及产品之间的性能差异;关键性能对比可能包括功耗与速度对比、上电浪涌电流测试情况说明、GTH Channel Loss性能差异说明、GTH电源性能差异说明等。此外,手册可能还提供了其他推荐应用方案,例如不使用的BANK接法推荐、CCLK信号PCB布线推荐、JTAG级联PCB布线推荐、系统工作的复位方案推荐等,这些内容对于提高系统性能稳定性有着重要作用。 焊接及注意事项章节则针对产品的焊接过程提供了指导,强调焊接过程中的注意事项,以确保产品在组装过程中的稳定性可靠性。手册还明确指出,未经复旦微电子的许可,不得翻印或者复制全部或部分本资料的内容,且不承担采购方选择与使用本文描述的产品服务的责任。 上海复旦微电子集团股份有限公司拥有相关的商标知识产权。该公司在中国发布的技术手册,版权为上海复旦微电子集团股份有限公司所有,未经许可不得进行复制或传播。 技术手册提供了上海复旦微电子集团股份有限公司销售及服务网点的信息,方便用户在需要时能够联系到相应的服务机构,获取最新信息必要的支持。同时,用户可以访问复旦微电子的官方网站(***以获取更多产品信息公司动态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值