一. delegate

C#代理实际上类似于C++中的函数指针,因为C#中不存在指针,所以用代理可以完成一些原来在C++中用函数指针完成的操作,例如传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m。但与函数指针相比,delegate有许多函数指针不具备的优点。首先,函数指针只能指向静态函数,而delegate既可以引用静态函数,又可以引用非静态成员函数。在引用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。其次,与函数指针相比,delegate是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime能够保证delegate指向一个有效的方法,你无须担心delegate会指向无效地址或者越界地址。

通过以下3个步骤即可实现一个delegate:

1. 声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。

声明一个代理的例子:

public delegate int MyDelegate(string message);

2. 创建delegate对象,并将你想要传递的函数作为参数传入。

创建代理对象的方法:

1). MyDelegate myDelegate = new MyDelegate(实例名.方法名);

2). MyDelegate myDelegate = new MyDelegate(类名.方法名);

注:如果需要代理的方法是一个static静态方法的话,采用第2种方式,否则采用第1种方式。

3. 在要实现异步调用的地方,通过上一步创建的对象来调用方法。

可以直接使用代理调用代理所指向的方法:

myDelegate(向方法传递的参数);

下面是一些需要注意的事情:

“代理”(delegate)(代表、委托):“代理”是类型安全的并且完全面向对象的。

(1)在C#中,所有的代理都是从System.Delegate类派生的(delegate是System.Delegate的别名)。

(2)代理隐含具有sealed属性,即不能用来派生新的类型。

(3)代理最大的作用就是为类的事件绑定事件处理程序。

(4)在通过代理调用函数前,必须先检查代理是否为空(null),若非空,才能调用函数。(5)在代理实例中可以封装静态的方法也可以封装实例方法。

(6)在创建代理实例时,需要传递将要映射的方法或其他代理实例以指明代理将要封装的函数原型(.NET中称为方法签名:signature)。注意,如果映射的是静态方法,传递的参数应该是类名.方法名,如果映射的是实例方法,传递的参数应该是实例名.方法名。

(7)只有当两个代理实例所映射的方法以及该方法所属的对象都相同时,才认为它们是想等的(从函数地址考虑)。

(8)多个代理实例可以形成一个代理链,System.Delegate中的定义了用来维护代理链的静态方法Combion,Remove,分别向代理链中添加代理实例和删除代理实例。

(9)代理的定义必须放在任何类的外面,如delegate int MyDelegate();而在类的方法中调用MyDelegate d = new MyDelegate(MyClass.MyMethod);来实例化自定义代理的实例。

(10)代理三步曲:

a.生成自定义代理类:delegate int MyDelegate();

b.然后实例化代理类:MyDelegate d = new MyDelegate(MyClass.MyMethod);

c.最后通过实例对象调用方法:int ret = d();

using System;

public class InstanceMethod

{

    public int Result1(string name)

    {

        Console.WriteLine("Instance:" + name);

        return ;

    }

    public static void Result2()

    {

        Console.WriteLine("Static");

    }

}

public class class1

{

    public delegate int DelHandler(string name);

    public delegate void DelHandler2();

    public static DelHandler2 Del = null;

    public static void Main(string[] args)

    {

        InstanceMethod ins = new InstanceMethod();

        DelHandler del = new DelHandler(ins.Result1);

        int result = del("a");

        Console.WriteLine(result.ToString());

        DelHandler2 del2 = new DelHandler2(InstanceMethod.Result2);

        del2();

        Del += Display;

        Del();

        Console.ReadLine();

    }

    private static void Display()

    {

        Console.WriteLine("Good Night!");

    }

}

二:event

例1

事件是特殊类型的多路广播委托,仅可从声明它们的类或结构(发行者类)中调用。如果其他类或结构订阅了该事件,则当发行者类引发该事件时,会调用其事件处理程序方法。

可以看出,C#中的event是通过delegate实现的,event 只是在delegate基础上作了两点限制:
1:客户只能使用委托所提供的+=和-=行为,不能直接用=,即不影响委托对其他observer的notify.
2:只有声明类可以调用(或激发)一个事件,外部类不可以直接调用其事件。
在一个C#接口中可以包容方法、C#属性以及索引器,也可以包容事件,但不能包含委托,因为接口定义的是成员,委托定义的是一个类型,而事件同样是成员。

using System;

namespace CSharpConsole

{

    //http://topic.csdn.net/t/20040903/17/3338252.html

    //定义委托处理程序

    public delegate void PlayGameHandler(object sender, System.EventArgs e);

    public class 场景

    {

        [STAThread]

        public static void Main(string[] args)

        {

            Console.WriteLine("场景开始了.");

            //生成小王

            小王 w = new 小王();

            //生成小账

            小张 z = new 小张();

            //指定监视

            z.PlayGame += new PlayGameHandler(w.扣钱);

            //开始玩游戏

            z.玩游戏();

            Console.WriteLine("场景结束");

            Console.ReadLine();

        }

    }

    //   负责扣钱的人   

    public class 小王

    {

        public 小王()

        {

            Console.WriteLine("生成小王");

        }

        public void 扣钱(object sender, EventArgs e)

        {

            Console.WriteLine("小王:好小子,上班时间胆敢玩游戏");

            Console.WriteLine("小王:看看你小子有多少钱");

            小张 f = (小张)sender;

            Console.WriteLine("小张的钱:" + f.钱.ToString());

            Console.WriteLine("开始扣钱");

            System.Threading.Thread.Sleep();

            f.钱 = f.钱 - ;

            Console.WriteLine("扣完了.现在小张还剩下:" + f.钱.ToString());

        }

    }

    //如果玩游戏,则引发事件

    public class 小张

    {

        //先定义一个事件,这个事件表示“小张”在玩游戏。

        public event PlayGameHandler PlayGame;

        //保存小张钱的变量   

        private int m_Money;

        public 小张()

        {

            Console.WriteLine("生成小张.");

            m_Money = ;   //构造函数,初始化小张的钱。

        }

        public int 钱   //此属性可以操作小张的钱。   

        {

            get

            {

                return m_Money;

            }

            set

            {

                m_Money = value;

            }

        }

        public void 玩游戏()

        {

            Console.WriteLine("小张开始玩游戏了..");

            Console.WriteLine("小张:CS好玩,哈哈哈!   我玩..");

            System.Threading.Thread.Sleep();

            System.EventArgs e = new EventArgs();

            OnPlayGame(e);

        }

        protected virtual void OnPlayGame(EventArgs e)

        {

            if (PlayGame != null)

            {

                PlayGame(this, e);

            }

        }

    }

}

例2

using System;

namespace nsEventSample

{

    ///   <summary>     

    ///   类EatEventArgs必须继承自类EventArgs,用来引发事件时封装数据     

    ///   </summary>     

    public class EatEventArgs : EventArgs

    {

        public String restrauntName;    //饭店名称

        public decimal moneyOut;        //准备消费金额

    }

    ///   <summary>

    ///   这个委托用来说明处理吃饭事件的方法的方法头(模式)

    ///   </summary>

    public delegate void EatEventHandler(object sender, EatEventArgs e);

    ///   <summary>

    ///   引发吃饭事件(EateEvent)的类Master(主人),这个类必须

    ///   1.声明一个名为EatEvent的事件:public event EatEventHandler EatEvent;

    ///   2.通过一个名为OnEatEvent的方法来引发吃饭事件,给那些处理此事件的方法传数据;

    ///   3.说明在某种情形下引发事件呢?在饿的时候。用方法Hungrg来模拟。

    ///   </summary>

    public class Master

    {

        //声明事件

        public event EatEventHandler EatEvent;

        //引发事件的方法

        public void OnEatEvent(EatEventArgs e)

        {

            if (EatEvent != null)

            {

                EatEvent(this, e);

            }

        }

        //当主人饿的时候,他会指定吃饭地点和消费金额。

        public void Hungry(String restrauntName, decimal moneyOut)

        {

            EatEventArgs e = new EatEventArgs();

            e.restrauntName = restrauntName;

            e.moneyOut = moneyOut;

            Console.WriteLine("主人说:");

            Console.WriteLine("我饿了,要去{0}吃饭,消费{1}元", e.restrauntName, e.moneyOut);

            //引发事件     

            OnEatEvent(e);

        }

    }

    ///   <summary>     

    ///   类Servant(仆人)有一个方法ArrangeFood(安排食物)来处理主人的吃饭事件

    ///   </summary>     

    public class Servant

    {

        public void ArrangeFood(object sender, EatEventArgs e)

        {

            Console.WriteLine();

            Console.WriteLine("仆人说:");

            Console.WriteLine("我的主人,   您的命令是   :   ");

            Console.WriteLine("吃饭地点   --   {0}", e.restrauntName);

            Console.WriteLine("准备消费   --   {0}元   ", e.moneyOut);

            Console.WriteLine("好的,正给您安排。。。。。。。。");

            Console.WriteLine("主人,您的食物在这儿,请慢用");

        }

    }

    ///   <summary>     

    ///   类God安排qinshihuang(秦始皇)的仆人是lisi(李斯),并让李斯的ArrangeFood     

    ///   方法来处理qinshihuang的吃饭事件:qinshihuang.EatEvent   +=   new   EatEventHandler(lishi.ArrangeFood);     

    ///   </summary>     

    public class God

    {

        public static void Main()

        {

            Master qinshihuang = new Master();

            Servant lishi = new Servant();

            qinshihuang.EatEvent += new EatEventHandler(lishi.ArrangeFood);

            //秦始皇饿了,想去希尔顿大酒店,消费5000元

            qinshihuang.Hungry("希尔顿大酒店", 5000.0m);

            Console.ReadLine();

        }

    }

}

例3

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

namespace ConsoleApplication8

{

    //http://www.cnblogs.com/xinjunjie/archive/2006/08/01/464944.html

    public class Program

    {

        static void Main(string[] args)

        {

            Clock c = new Clock();

            DisplayClock dis = new DisplayClock();

            dis.Subscribe(c);

            c.Run();

        }

    }

    public class DisplayClock

    {

        public void Subscribe(Clock clk)

        {

            clk.OnClock += new Clock.DisplayClock(clk_OnClock);

        }

        void clk_OnClock(object clock, TimerEventArgs args)

        {

            Console.WriteLine(args.hour + ":" + args.minutes + ":" + args.second);

        }

    }

    public class Clock

    {

        private int hour;

        private int minutes;

        private int second;

        public Clock()

        {

            hour = DateTime.Now.Hour;

            minutes = DateTime.Now.Minute;

            second = DateTime.Now.Second;

        }

        public delegate void DisplayClock(object clock, TimerEventArgs args);

        public event DisplayClock OnClock;

        public void Run()

        {

            while ( == )

            {

                Thread.Sleep();

                DateTime dt = DateTime.Now;

                if (dt.Second != second)

                {

                    if (OnClock != null)

                    {

                        OnClock(this, new TimerEventArgs(hour, minutes, second));

                    }

                }

                hour = DateTime.Now.Hour;

                minutes = DateTime.Now.Minute;

                second = DateTime.Now.Second;

            }

        }

    }

    public class TimerEventArgs : EventArgs

    {

        public readonly int hour;

        public readonly int minutes;

        public readonly int second;

        public TimerEventArgs(int h, int m, int s)

        {

            this.hour = h;

            this.minutes = m;

            this.second = s;

        }

    }

}

例4

using System;

using System.Collections.Generic;

using System.Text;

namespace UsingEvent

{

    public delegate void ClickEventHandler(object sender, EventArgs e);//声明一个代表:请看文章最后面Note

    public class MyButton              //创建MyBottom

    {

        public event ClickEventHandler ClickEvent;//声明一个事件

        public void Click()                                 //单击MyButton

        {

            if (ClickEvent != null)

            {

                Console.WriteLine("MyButton: 我被单击了");

                ClickEvent(this, null);                          //抛出事件,给所有相应者

            }

        }

    }

    public class MyForm

    {

        public MyButton myButton = new MyButton();

        public MyForm()

        {

            //添加事件到myButton中,当myButton被单击的时候就会调用相应的处理函数

            myButton.ClickEvent += new ClickEventHandler(OnClickEvent);

        }

        //事件处理函数

        void OnClickEvent(object sender, EventArgs e)

        {

            Console.WriteLine("MyForm: 我知道你被单击了!");

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            MyForm form = new MyForm();//生成一个MyForm

            form.myButton.Click();//单击MyForm中的鼠标,效果就出来了

            Console.ReadLine();

        }

    }

}

delegate和event的区别 (zz)的更多相关文章

  1. .NET 里delegate和event的区别

    最近一朋友找工作面试遇到这么个题目,正好我也对此有点模糊,遂进行了一番资料查询,找到了这个文章: http://www.cnblogs.com/chengxingliang/archive/2013/ ...

  2. Delegate成员变量和Event的区别

    上周五有同事问了我一个问题:Delegate和Event有什么区别?具体来说在设计一个类的时候,声明一个事件(Event)和声明一个Delegate类型的成员变量有啥区别.   我的第一反应是没啥区别 ...

  3. 第一章、C#委托和事件(Delegate、Event、EventHandler、EventArgs)

    第一章.C#委托和事件(Delegate.Event.EventHandler.EventArgs) 分类: 学习笔记-C#网络编程2012-12-08 14:10 7417人阅读 评论(3) 收藏  ...

  4. delegate和event

    经过查阅资料和自己的理解整理出来的,欢迎大家指教. delegate和event 何时使用: 异步的时候,比如加载完成通知. 需要回调的时候,比如按钮点击.动画播放结束等. 发送事件通知的时候. 比如 ...

  5. [转] C#中的delegate 和 event

    转至:here 终于会用c#中的delegate(委托) 作者:qq826364410 引言 Delegate是Dotnet1.0的时候已经存在的特性了,但由于在实际工作中一直没有机会使用Delega ...

  6. 浅谈c#中的delegate和event了

    一.开篇忏悔 对自己最拿手的编程语言C#,我想对你说声对不起,因为我到现在为止才明白c#中的delegate和event是怎么用的,惭愧那.好了,那就趁着阳光明媚的早晨简单来谈谈delegate和ev ...

  7. .NET 中易混淆的概念(Delegate vs Event)

    事件(event)是一个非常重要的概念,我们的程序时刻都在触发和接收着各种事件:鼠标点击事件,键盘事件,以及处理操作系统的各种事件.所谓事件就是 由某个对象发出的消息.比如用户按下了某个按钮,某个文件 ...

  8. 观察者模式与.NET的delegate、event机制

    1.引言 最近在写一些程序玩的时候,接触到了delegate(委托)和event(事件),网上查找了很多的资料,有些博文说可以把delegate近似当做C++当中的函数指针来看,由于自己本身对C++的 ...

  9. keyWindow与delegate中Window的区别

    keyWindow与delegate中Window的区别 源码: // // ViewController.m // UIWindowRelated // // Created by YouXianM ...

随机推荐

  1. KVM调整cpu和内存

    一.修改kvm虚拟机的配置 1.virsh edit centos7 找到“memory”和“vcpu”标签,将 <name>centos7</name> <uuid&g ...

  2. vue中使用ueditor富文本编辑框

    1.把下载的Ueditor资源,放入静态资源static中. 修改ueditor.config.js中的window.UEDITOR_HOME_URL配置,如下图: 2.在main.js中引入以下文件 ...

  3. 【JAVAWEB学习笔记】网上商城实战4:订单模块

    今日任务 完成订单模块的功能 1.1      订单 模块的功能 1.1.1    我的订单: [我的订单的查询] * 在header.jsp中点击我的订单. * 提交到Servlet: * 获得用户 ...

  4. spring完成自动装配

    让spring完成自动装配 Autowiring 解决标签为javaBean注入时难以维护而实现的 下面是几种autowire type的说明: 1,byname:试图在容器中寻找和需要自动装配的属性 ...

  5. 【BZOJ 2916】 2916: [Poi1997]Monochromatic Triangles (容斥)

    2916: [Poi1997]Monochromatic Triangles Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 310  Solved: 1 ...

  6. Codeforces 992 E. Nastya and King-Shamans

    \(>Codeforces\space992 E. Nastya and King-Shamans<\) 题目大意 : 给你一个长度为 \(n\) 的序列,有 \(q\) 次操作,每一次操 ...

  7. bzoj 1654: [Usaco2006 Jan]The Cow Prom 奶牛舞会 -- Tarjan

    1654: [Usaco2006 Jan]The Cow Prom 奶牛舞会 Time Limit: 5 Sec  Memory Limit: 64 MB Description The N (2 & ...

  8. 常用 iOS 开源库和第三方组件

    1.通过CocoaPods安装 项目名称 项目信息 AFNetworking 网络请求组件 FMDB 本地数据库组件 SDWebImage 多个缩略图缓存组件 UICKeyChainStore 存放用 ...

  9. centos安装pcre

    安装pcre前需要已安装gcc工具 1.跳转下载目录 cd install-file 2.下载pcre wget ftp://ftp.csx.cam.ac.uk/pub/software/progra ...

  10. HDU 4699 Editor (2013多校10,1004题)

    Editor Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Su ...