• 委托、事件学习笔记


      学习c#有一段时间了,在工作或者学习中总是碰到委托和事件,行内过来人说委托和事件其实就是一个坎,没过去的总感觉到委托和事件很难理解,而过去的人说也就是那么一回事。本人现在应该是处于正在理解的边缘,托大了,其实狗屁都没理解。关于委托和事件,在网上也看了大量的资料,大牛们好像是每个牛都有自己的理解,小可也只能模仿学习,此文仅仅记录自己的学习笔记。如有侵犯大牛的地方,还望海涵。

    委托:

      委托,开始的理解是将方法作为一个函数的参数进行调用。这种理解是正确的,只是站在表皮上。前几天又听一同事的讲解,别有一番风味。

      “当一个类或者是进程需要调用一个方法时,需要借助另外的类或者是进程进行调用,而这种机制就称为委托”。

      两种理解本质上是一样的,但是站的高度不一样,对问题的理解肯定不能同日而语。还有牛说:委托可以理解成为函数指针,不同的是委托是面向对象的,而且是类型安全的。

    委托使用的三个步骤:

      1、声明一个委托: public delegate void processDelegate;

      2、定义一个委托对象:processDelegate pro= new processDelegate(需要调用的方法);

      3、调用方法:pro(i);

    下面是一个委托示例:

    public partial class MainWindow : Window
        {
            public delegate void processDelegate(int value);
            processDelegate pro = null;
            public MainWindow()
            {
                InitializeComponent();
                Thread t = new Thread(new ThreadStart(gogogo));
                t.Start();
    
                pro = new processDelegate(this.process);
            }
    
            public void process(int value)
            {
                this.progressBar1.Dispatcher.Invoke(new Action(()=>{ progressBar1.Value = value;
                tbText.Text = "执行";
                }));
            }
    
    
            public void gogogo()
            {
                for (int i = 0; i < 100; i++)
                {
                    if (pro != null)
                    {
                        pro(i);
                    }
                    System.Threading.Thread.Sleep(100);
                }
            }
        }
    
    
    <Grid>
            <ProgressBar Height="35" HorizontalAlignment="Left" Margin="84,109,0,0" Name="progressBar1" Minimum="1" Maximum="100" VerticalAlignment="Top" Width="302" />
        </Grid>
    View Code


    事件:

      事件可以分为两个部分:事件发送器和事件接收器。事件发生类:这个类中触发了一个事件,但这个类并不知道哪个对象或者方法将会接收并处理它。现在就需要发送方和接收方之间存在一个媒介。而媒介就是委托。

       下面具体拿一个例子来说明如何使用事件:

      定义一个发送器的类:KeyInputMonitor

      声明委托和事件:public delegate void KeyDownHanlder(object sender, keyEventArgs e);
                   public event KeyDownHanlder KeyDown;

      在KeyInputMonitor类中定义一个方法Run,在方法内部触发事件:KeyDown (this ,myKeyEventArgs );

      定义一个接收器的类:EventReceiver

      类产生一个委托实例,并把这个委托实例添加到产生事件对象的事件列表中:monitor.KeyDown += new KeyInputMonitor.KeyDownHanlder(monitor_KeyDown);

      委托调用的方法,也是真正的处理函数:monitor_KeyDown

      完整代码:

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Event
    {
        class Program
        {
            static void Main(string[] args)
            {
                KeyInputMonitor myMonitor = new KeyInputMonitor();
    
                EventReceiver myReceiver = new EventReceiver(myMonitor);
    
                myMonitor.Run();
            }
        }
    
        //派生一个KeyEventArgs类,来保存按键信息
        class keyEventArgs : EventArgs
        {
            private char keyChar;
            public keyEventArgs(char KeyChar)
                : base()
            {
                this.keyChar = KeyChar;
            }
    
            public char KeyChar
            {
                get { return keyChar; }
            }
        }
    
        class KeyInputMonitor
        {
            public delegate void KeyDownHanlder(object sender, keyEventArgs e);
            public event KeyDownHanlder KeyDown;
    
            public void Run()
            {
                bool finished = false;
    
                do
                {
                    Console.WriteLine("input a char...");
                    string response = Console.ReadLine();
    
                    char responseChar = (response == "") ? '':char.ToUpper (response [0]);
                    switch (responseChar )
                    {
                        case 'X':
                            finished = true ;
                            break ;
                        default :
                            keyEventArgs myKeyEventArgs = new keyEventArgs (responseChar );
                            KeyDown (this ,myKeyEventArgs );//触发事件
                            break ;
                    }
                }while (!finished);
            }
        }
    
        //类先产生一个委托实例,再把这个委托实例添加到产生事件对象的事件列表中去,这个过程又叫订阅事件
        class EventReceiver
        {
            public EventReceiver(KeyInputMonitor monitor)
            {
                monitor.KeyDown += new KeyInputMonitor.KeyDownHanlder(monitor_KeyDown);
            }
    
            void monitor_KeyDown(object sender, keyEventArgs e)
            {
                //真正的事件处理函数
                Console.WriteLine("capture key:{0}", e.KeyChar);
            }
        }
    }
    View Code


    暂且写到此处,如果在以后有更深层次的理解,再次更改补充吧。

    补充1:

    委托和事件的区别:

    委托:明面上是将方法作为一个函数的参数进行调用,另外一种理解是:当一个类或者是进程需要调用一个方法是,需要借助另外的类或者进程进行调用,这种机制成为委托。本质上来讲:委托是一种类型。

    事件是一种特殊的委托类型。

    委托和事件的区别:委托可以直接调用委托来激发委托所指向的函数,也可以由服务代码自己触发。事件的触发只能由服务代码自己触发。

    通俗来说:委托可以从类内和类外进行调用注册的方法;事件只能从类内调用注册的方法,比委托要安全。

    补充2:

    1)委托定义:

    委托类似于 C 或 C++ 中的函数指针。使用委托将方法引用封装在委托对象内,然后调用该委托对象就可以执行委托对象内方法引用指向的方法,而不必在编译时知道将调用哪个方法。

    2)委托本质:

    1.声明委托

    public delegate void SayHelloDelegate(string who);

    2.使用ILSpy反编译后,看其本质

    public class auto ansi sealed SayHelloDelegate: MulticastDelegate

    编译器自动生成了一个委托类,继承自MulticastDelegate。

    3.下图可以说明:

    3)调用委托:

    1.给委托变量加上()就相当于调用

    static void Main(string[] args)
    {
    //创建委托变量(使用new关键字)
    SayHelloDelegate sayDel = new SayHelloDelegate(SayHelloToAmerican);
    
    //委托变量调用
    sayDel("jack");
    }

    2.反编译看其本质是调用了Invoke方法
    所以我们自己也可以直接调用这个方法,委托变量调用的这两种方法,本质是一样的,编译器都会调用Invoke。简写方式也是语法糖。

    sayDel("jack");
    sayDel.Invoke("jack");

    3.委托变量的调用本质上通过反射对方法的调用
    这是委托的构造函数,有两个参数

    public SayHelloDelegate(object target, string method)
    {
    }

    委托类同时提供了两个只读属性Target和Method供使用,是将委托变量指向的对象和方法进行了包装,如果方法是静态方法,则Target为null,否则就指向对象的引用。Method属性返回一个System.Reflection.MethodInfo对象的引用。在我们调用Invoke方法时,其实是执行了委托变量指向的方法,只不过有一个内部包装和调用的机制。

    补充:

    经过一段时间的学习,在本博文的基础上写了一篇:

    委托学习笔记后续:泛型委托及委托中所涉及到匿名方法、Lambda表达式

    引用:

    委托的使用与原理简析

      

    最新博客信息,请关注“小项目笔记”公众号;
  • 相关阅读:
    Django框架---- 自定义分页组件
    Django框架----Form组件补充
    ARM体系的异常中断
    ARM处理机模式--内部寄存器
    产品概述
    简单应用程序的设计 -重复前缀
    简单应用程序的设计字符串处理
    基本输入输出系统BIOS---显示输出
    基本输入输出系统BIOS---键盘输入
    中断
  • 原文地址:https://www.cnblogs.com/ysyn/p/3284345.html
Copyright © 2020-2023  润新知