c# delegate ,event

首先说明,event其实也是一种delegate,为了区分,我们称一般的delegate为“plain delegate”。

写代码的过程中,经常会在delegate和event之间进行选择,以前也没仔细思考选择的原因,今天终于忍不住花了半天时间仔细琢磨了一下……好了,直接拿代码说话吧:

using System;

namespace EventAndDelegate
{
    public delegate void TestDelegate(string s);

    public interface ITest {
        // 【区别】 1. event可以用在interface中,而plain delegate不可以(因为它是field)
        event TestDelegate TestE;   // Passed
        TestDelegate TestD;         // Error: Interfaces cannot contain fields
    }

    public class Parent {
        public event TestDelegate TestE;
        public TestDelegate TestD;

        protected void RaiseTestE(string s)
        {
            TestE(s);   // The event ‘EventAndDelegate.Parent.TestE‘ can only
                        // be used from within the type ‘EventAndDelegate.Parent‘
        }
    }

    public class Child : Parent {
        void ChildFunc()
        {
            // 【区别】 2. event不允许在声明它的class之外(即使是子类)被调用(除此之外只能用于+=或-=),而plain delegate则允许
            TestD("OK");        // Passed
            TestE("Failure");   // Error: The event ‘EventAndDelegate.Parent.TestE‘ can only appear on
                                //        the left hand side of += or -= (except when used from within
                                //        the type ‘EventAndDelegate.Parent‘)

            // 【补充】 在子类中要触发父类声明的event,通常的做法是在父类中声明一个protected的Raisexxx方法供子类调用
            RaiseTestE("OK");   // The class ‘EventAndDelegate.Child‘ can only call the
                                // ‘EventAndDelegate.ParentRaiseTestE‘ method to raise the event
                                // ‘EventAndDelegate.Parent.TestE‘

            // 【区别】 同2#
            object o1 = TestD.Target;
            object o2 = TestE.Target;   // The class ‘EventAndDelegate.Child‘ can only call the
                                        // ‘EventAndDelegate.ParentRaiseTestE‘ method to raise the event
                                        // ‘EventAndDelegate.Parent.TestE‘

            // 【区别】 同2#
            TestD.DynamicInvoke("OK");
            TestE.DynamicInvoke("OK");   // The class ‘EventAndDelegate.Child‘ can only call the
                                        // ‘EventAndDelegate.ParentRaiseTestE‘ method to raise the event
                                        // ‘EventAndDelegate.Parent.TestE‘
        }
    }

    class Other
    {
        static void Main(string[] args)
        {
            Parent p = new Parent();

            p.TestD += new TestDelegate(p_Test1);   // Passed
            p.TestE += new TestDelegate(p_Test1);   // Passed

            // 【区别】 3. event不允许使用赋值运算符,而plain delegate则允许。
            //             注意,对plain delegate,使用赋值运算符意味着进行了一次替换操作!
            p.TestD = new TestDelegate(p_Test2);   // Passed
            p.TestE = new TestDelegate(p_Test2);   // Error: The event ‘EventAndDelegate.Parent.TestE‘ can only appear on
                                                   //        the left hand side of += or -= (except when used from within
                                                   //        the type ‘EventAndDelegate.Parent‘)

            // 【区别】 同2#
            p.TestD("OK");      // Passed
            p.TestE("Failure"); // Error: The event ‘EventAndDelegate.Parent.TestE‘ can only appear on
                                //        the left hand side of += or -= (except when used from within
                                //        the type ‘EventAndDelegate.Parent‘)
        }

        static void p_Test1(string s)
        {
            Console.WriteLine("p_Test1: " + s);
        }

        static void p_Test2(string s)
        {
            Console.WriteLine("p_Test2: " + s);
        }
    }
}

分析:

  1. plain
    delegate与event的关系类似于field与Property(实事上前者就是field,或者我们可以把event看成是一种特殊的Property)
  2. 正是由于1#,在使用上,plain delegate几乎没有任何限制,而event则有严格的限制(只能用在+=和-=的左边)

结论

    1. event更面向对象一些。
    2. 当我们需要灵活时,直接使用plain delegate;反之,需要严格的控制时,使用event。
    3. 由于event不能使用赋值运算符,因此有时我们要求一个事件在任何时刻只能有一个响应方法时,我们使用plain delegate更为方便。
时间: 2024-11-04 19:47:57

c# delegate ,event的相关文章

delegate, event - 里面涉及的参数类型必须完全一致,子类是不行的

public void TestF() { Test += Fun; } public void Fun(Person p) { }  // 如 Person变成 SubPerson,则报错..public void Fun(SubPerson p) { } public event Action<Person> Test; delegate, event - 里面涉及的参数类型必须完全一致,子类是不行的

delegate&amp;event学习理解

一. //声明的委托 public delegate void BoilerLogHandler(string status); // 基于上面的委托定义事件 public event BoilerLogHandler BoilerEventLog; //main方法 static void Main(string[] args) { BoilerInfoLogger filelog = new BoilerInfoLogger(@"E:\\boiler.txt"); Delegate

Delegate&amp;Event

Delegate 1.基本类: 1 public class Student 2 { 3 public int Id { get; set; } 4 public string Name { get; set; } 5 6 public void Study() 7 { 8 Console.WriteLine("学习.net高级班公开课"); 9 } 10 11 public void StudyAdvanced(string name) 12 { 13 Console.WriteLi

c#中的delegate(委托)和event(事件)

委托: 托付其他人做这件事   ,包括 托付自己  ,即  一个方法 可以  调用 没有关系的其他方法 , 也可以 将委托传递过去 ,回调自己的方法 ,且 可以自定义参数 ,非常方便 互相传值, 适合解耦 关系. 示例: public delegate void ChangeMoney(object s, int n);   // 用 delegate  声明委托 1. 调用 其他方法 售卖 页面添加商品,添加 的 商品 在另一个页面也能看见 . 售卖页面 类里面 定义委托: //定义一个委托 

C#学习日记24----事件(event)

事件为类和类的实例提供了向外界发送通知的能力,实现了对象与对象之间的通信,如果定义了一个事件成员,表示该类型具有 1.能够在事件中注册方法 (+=操作符实现). 2.能够在事件中注销方法(-=操作符实现). 3.当事件被触发时注册的方法会被通知(事件内部维护了一个注册方法列表).委托(Delegate)是事件(event)的载体,要定义事件就的要有委托.  有关委托的内容请点击 委托(De... www.mafengwo.cn/event/event.php?iid=4971258www.maf

Liferay7 BPM门户开发之4: Activiti事件处理和监听Event handlers

事件机制从Activiti 5.15开始引入,这非常棒,他可以让你实现委托. 可以通过配置添加事件监听器,也可以通过Runtime API加入注册事件. 所有的事件参数子类型都来自org.activiti.engine.delegate.event.ActivitiEvent 包含的信息: type executionId processInstanceId processDefinitionId 事件监听 其中,JOB_EXECUTION_SUCCESS 和JOB_EXECUTION_FAIL

C# 部分语法总结(入门经典)

class Program { static void Main(string[] args) { init(); System.Console.ReadKey(); } #region 接口 /// <summary> /// 接口成员是公共的,不能加其他修饰符,如static,public,virtual等 /// </summary> public interface IA { string IStr { get; set; } void IMethod(); } publi

target/action 设计模式

Target-Action模式是ObjC里非常常见的对象之间方法调用的方式,不过ObjC把方法调用叫做Send Message. 一帮情况在和UI打交道时候处理各种GUI上的事件会利用到这种模式.相对应的.NET上的处理模式就是delegate/event了. 不过,Target-Action拜C语言所赐,更是灵活很多,编译期没有任何检查,都是运行时的绑定. 看代码 首先我们创建一个继承UIView的类 1 #import <UIKit/UIKit.h> 2 3 @interface Touc

DOM事件简介

Click.touch.load.drag.change.input.error.risize — 这些都是冗长的DOM(文档对象模型)事件列表的一部分.事件可以在文档(Document)结构的任何部分被触发,触发者可以是用户操作,也可以是浏览器本身.事件并不是只是在一处被触发和终止:他们在整个document中流动,拥有它们自己的生命周期.而这个生命周期让DOM事件有更多的用途和可扩展性. 作为一个开发人员,我们必须要理解DOM事件是如何工作的,然后才能更好的驾驭它,利用它们潜在的优势,开发出