委托、事件学习笔记

  学习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 == "") ? '\0':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表达式

 

引用:

委托的使用与原理简析

 

  

posted @ 2013-08-28 09:45  小项目笔记  阅读(1144)  评论(1编辑  收藏  举报

更多文章请关注公众号:小项目笔记

小项目笔记