用来容纳字段数据的动态内存是在项目对象中分红的,一旦事件暴发

首先步:首先,其他对象订购事件

       当发球的球员爆发它的发球事件此前,其他球员需要预订这一个事件,拔取那种办法,只要出现一个发球事件,其他球

员就可知清楚。

 

(三)  封装事件访问器及成员

4.依次对象订购事件

style=”font-size: large;”>一旦确立了事件处理程序,其他球员对象需要关联他们友善的事件处理程序。每个对象都有温馨一定的

style=”font-size: large;”>sendPlayer_Play方法,对这多少个事件做出不同的响应。所以,

style=”font-size: large;”>假使有一个SendPlayer对象引用变量或字段,名为sendPlayer,可以用+=操作符关联事件处理程序:

 

sendPlayer.Play+=new
EventHandler(sendPlayer_Play);

(二) 字段

1.大家需要一个标示事件参数的对象

       
要铭记在心,Play事件(我们下边把发球事件都说成play事件)有局部亟需指导的参数。所以我们需要一个大概的对象来代表那个参数。

为此,.NET
提供了一个标准的类,名为伊芙ntArgs,然则那些类没有其余成员。它的目的唯有一个,就是同意将你的风波的参数对象传

递到事件事件处理程序再说运用。
以下是事件参数类的扬言:

     public class
BallEventArgs:EventArgs

 

  应该在伊夫(Eve)ntArgs派生类中为事件处理程序提供参数,并将这么些参数作为类成员。委托类中遍历他的订阅者列表,将参数对象在订阅者中各类传递。但不可以预防某个订阅者修改参数值,进而影响其后拥有的处理事件的订阅者。平日意况下,当这多少个分子在订阅者中传送时,应防范订阅者对其开展修改,可将参数的访问权限设置为只读,或当面这多少个参数为国有成员,并使用readonly访问修饰符,在这二种状态下,都应有在构造器中起首化这个参数。

第五步:各个对象处理事件

          
现在,其他球员都会以她们自己的点子处理发球事件。但是并不是还要运行—他们的事件处理程序会先后得到调用,并以

Ball伊芙ntArgs对象的一个引用作为参数。     

 

    public event
EventHandler<CostomEventArgs> CostomEvent;

第四步:订购者得到通告   

            由于其它球员对象都预订了发球球员对象的发球事件,所以这么些目的会拿到关照,并先后调用他们的事件处理方法。事件处

理程序就是发出事件时订购者对象运行的措施,一旦发球者爆发了其事件,就会创制一个Ball伊夫ntArgs对象,其中蕴含球的轨迹

和距离,从而将个目的传递到订购者的事件处理程序。

(四) 事件的精神

5.SendPlayer对象暴发一个风波通报订购者球赛开端。

style=”font-size: large;”>既然已经创办事件,那么触发那么些事件就很容易,只需要调用Play事件。

if(Play!=null)

Play(this,e);

style=”font-size: large;”>基本的手续都有了,我们可以遵从步骤写自己的轩然大波了。

2 隐式实现事件

其次步:触发事件

       当球被暴发时,此时发球员对象暴发一个新事件。

 

  Costom伊夫(Eve)ntReleaser中拔取以下代码定义事件:

2.接下来需要在发生事件的类中定义这一个事件

     
我们在SendPlayer类中(就是发球球员类,汗,英文不是太好,见谅)定义一个风波,以便其他对象订购这些事件。

扬言如下:

      public event EventHandler
Play;

style=”font-size: large;”>event关键字背后的伊芙ntHandler不是C#的保留字,它是.NET提供的。之所以需要它,是为了告知订购事件的对象。

style=”font-size: large;”>他们的事件处理方法应该是何等体统(有什么的署名)

style=”font-size: large;”>即他们的事件处理程序应该有两个参数,一个参数是名为sender的object,另一个参数是名为e的伊夫ntArgs引用。

其三步
定义负责吸引风波的法子来打招呼事件的挂号

下面大家解析下把各样部分连接起来

首先步 自定义事件参数

3.订购类需要事件处理方法

         
订购SendPlayer的Play事件的次第对象都亟需一个事件处理程序。其实大家早已明白事件处理程序是何等工作的,

您拉一个Button,然后双击它,IDE就活动给你扩大一个click事件。所以Play的风波你看起来应当很熟练。

          

             void 
sendPlayer_Play(object sender,EventArgs e)

style=”font-size: large;”>C#中并不曾规则要求事件处理程序必须按某种格局命名,不过这是一种非凡标准的命名约定:首先是目的引用名,

style=”font-size: large;”>前边一个下划线,再前边是事件名。

  综上所述,除非需要在编译期间得到适当的数值以外,其它情况,都应该尽可能利用运行时常量。

style=”font-size: large;”>在上一篇观看他自家刹那间就悟了(续)—委托,被人狂喷。说写的太空,没有怎么内容之类的。所以准备在此间重写下, style=”font-size: large;”>可是仍然按着 style=”font-size: large;”>往日的艺术尽量简单的写。这里我们以打篮球为例。

  .Net和其它第三方框架补助松耦合事件,在.NET中定义松耦合事件可以参考MSDN中关于System.EnterpriseServices.Service(Service)dComponent的相关内容。

其三步:球暴发一个事变

        
创造一个新事件,这一个事件还有局部参数,如球的相距和轨迹。这么些参数作为伊夫(Eve)ntArgs对象的一个实例关联到事件,然后

事件暴发,所有监听目的都能得到这些事件。一旦事件时有暴发,所有订购者都会博得关照,并做一些拍卖。

  下例显示了咋样利用事件:

  CLR援助项目字段和实例字段。对于项目字段,用于容纳字段数据的动态内存是在类型对象中分红的,而项目对象是在项目加载到一个AppDomain时创建的;对于实例字段,用于容纳字段数据的动态内存则是在构造类型的一个实例时分配的。字段解决了版本控制问题,其值存储在内存中,只有在运作时才能得到。

  • 编译期常量的值在编译时取得,而运作时常量的值在运转时拿到。
  • 双方访问模式各异。编译期常量的值是在目的代码中展开互换的,而运行时常量将在运转时求值,引用运行时常量生成的IL将引用到readonly的变量,而不是变量的值。由此,编译期常量的性能更好,而运作时常量更为灵活。
  • 编译期常量仅帮忙整型、浮点型、枚举和字符串,其余值类型如Date提姆e是无力回天开头化编译期常量的。可是,运行时常量则帮助任何项目。
  • 编译期常量是静态常量,而运行时常量是实例常量,可以为品种的每个实例存放不同的值。

  以上代码存在下列问题——发表类需要将委托成员公开为公共成员变量,这样具有出席方都可以向该信托列表添加订阅者,公共的信托成员打破了包装,导致代码应用程序安全风险。因而为了化解该问题,并简化编码微软提交了event来细化作为事件订阅和通报使用的信托项目。将委托成员变量定义为事件后,即使该成员为国有成员,也仅有发布类(不包括子类)可以起身此事件(即便任何人都能够向该信托列表添加目的措施)。由揭橥类的开发者来控制是否提供一个共用艺术来触发该事件。使用事件代表本来委托还会下滑公布者与订阅者间的松耦合,因为宣布者触发事件的事体逻辑对订阅者是东躲西藏的。

    class Program
    {
        static void Main(string[] args)
        {
            Bell bell = new Bell();
            bell.RingList = new Bell.Ring(CallWhenRingA);
            bell.Rock(1);
            //赋值新对象
            bell.RingList = new Bell.Ring(CallWhenRingB);
            bell.Rock(2);
            //直接调用委托
            bell.RingList.Invoke(3);

            Console.ReadLine();
        }

        static void CallWhenRingA(int times)
        {
            Console.WriteLine("A"+times);
        }

        static void CallWhenRingB(int times)
        {
            Console.WriteLine("B" + times);
        }
    }

    public sealed class Bell
    {
        public delegate void Ring(int times);

        public Ring RingList;

        public void Rock(int times)
        {
            if (RingList != null)
            {
                RingList(times);
            }
        }
    }

  除了生成上述3个结构,编译器还会在托管程序集的元数据中生成一个风波定义纪录项。这个记录项包含部分标志和基础委托项目,还引用了add和remove访问器方法。这一个音讯的效果是树立“事件”的抽象概念和它的访问器方法之间的维系。编译器和其他工具得以选拔这一个元数据新闻,并可通过System.Reflection.伊芙(Eve)ntInfo类获取这些信息。不过,CLR本身并不接纳这一个音信,它在运转时只需要访问器方法。

(五)
事件与自定义处理函数的设计

  readonly和const本质上都是常量,readonly是运行时常量而const是编译期常量。三种常量具有以下分别:

  下边代码显示了那种艺术的助益,仅透过五回调用就足以通报所有接口,并展现了对事件类成员的一心封装。

(二) 管理大量事变

  常量总是被视为静态成员,而不是实例成员。定义常量将招致创制元数据。代码引用一个常量时,编译器会在概念常量的次第集的元数据中查找该符号,提取常量的值,并将值嵌入IL中。由于常量的值直接嵌入IL,所以在运转时不需要为常量分配任何内存。另外,无法博得常量的地点,也无法以传递引用的方法传递常量。这个限制意味着,没有很好的跨程序集版本控制特性。因而,唯有在规定一个标志的值从不变化时,才应该采用。假若指望在运行时从一个先后集中提取一个先后集中的值,那么不应当接纳常量,而相应使用
readonly 字段。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            CostomEventPublisher cep = new CostomEventPublisher();
            CostomEventListener cel = new CostomEventListener();
            cep.Subscribe(cel, EventType.OnAllEvents);
            cep.FireEvent(EventType.OnClick, "Click:Hello");
            cep.FireEvent(EventType.OnDoubleClick, "Double:Word");
            Console.ReadLine();
        }
    }

    //自定义事件参数
    public sealed class CostomEventArgs : EventArgs
    {
        private readonly string message;

        public string Message
        {
            get { return message; }
        }

        public CostomEventArgs(string message)
        {
            this.message = message;
        }
    }

    //定义监听者接口
    public interface ICostomEventListener
    {
        void OnClick(object sender, CostomEventArgs eventArgs);
        void OnDoubleClick(object sender, CostomEventArgs eventArgs);
    }

    //定义事件类型枚举
    [Flags]
    public enum EventType
    {
        OnClick = 0x01,
        OnDoubleClick = 0x02,
        OnAllEvents = OnClick | OnDoubleClick
    }

    //定义事件发布者
    internal class CostomEventPublisher
    {
        EventHandlerList eventList;
        static object eventClickKey = new object();
        static object eventDoubleClickKey = new object();

        public CostomEventPublisher()
        {
            eventList = new EventHandlerList();
        }

        //定义事件
        public event EventHandler<CostomEventArgs> Click
        {
            add
            {
                eventList.AddHandler(eventClickKey, value);
            }
            remove
            {
                eventList.RemoveHandler(eventClickKey, value);
            }
        }
        public event EventHandler<CostomEventArgs> DoubleClick
        {
            add
            {
                eventList.AddHandler(eventDoubleClickKey, value);
            }
            remove
            {
                eventList.RemoveHandler(eventDoubleClickKey, value);
            }
        }

        //引发事件
        protected virtual void OnEvent<T>(T e, EventHandler<T> eventDelegate) where T : EventArgs
        {
            e.Raise(this, ref eventDelegate, false);
        }

        //添加事件监听
        public void Subscribe(ICostomEventListener listener, EventType type)
        {
            if ((type & EventType.OnClick) == EventType.OnClick)//判断是否包含某个枚举值
            {
                this.Click += listener.OnClick;
            }
            if ((type & EventType.OnDoubleClick) == EventType.OnDoubleClick)
            {
                this.DoubleClick += listener.OnDoubleClick;
            }
        }

        //移除事件监听
        public void Unsubscribe(ICostomEventListener listener, EventType type)
        {
            if ((type & EventType.OnClick) == EventType.OnClick)
            {
                this.Click -= listener.OnClick;
            }
            if ((type & EventType.OnDoubleClick) == EventType.OnDoubleClick)
            {
                this.DoubleClick -= listener.OnDoubleClick;
            }
        }

        //构造参数实例,并引发事件
        public void FireEvent(EventType type, string message)
        {
            CostomEventArgs e = new CostomEventArgs(message);
            if ((type & EventType.OnClick) == EventType.OnClick)
            {
                OnEvent(e, eventList[eventClickKey] as EventHandler<CostomEventArgs>);
            }
            if ((type & EventType.OnDoubleClick) == EventType.OnDoubleClick)
            {
                OnEvent(e, eventList[eventDoubleClickKey] as EventHandler<CostomEventArgs>);
            }
        }
    }

    //扩展方法封装线程安全逻辑
    public static class EventArgExtensions
    {
        public static void Raise<T>(this T e, Object sender, ref EventHandler<T> eventDelegate, bool ifIgnoreException) where T : EventArgs
        {
            EventHandler<T> temp = Interlocked.CompareExchange(ref eventDelegate, null, null);
            if (temp != null)
            {
                if (!ifIgnoreException)
                {
                    try
                    {
                        temp(sender, e);
                    }
                    catch
                    {
                        //TODO:处理异常
                    }
                }
                else
                {
                    Delegate[] delegates = temp.GetInvocationList();
                    foreach (Delegate del in delegates)
                    {
                        try
                        {
                            temp(sender, e);
                        }
                        catch
                        { }
                    }
                }
            }
        }
    }

    //定义监听者
    internal sealed class CostomEventListener : ICostomEventListener
    {
        //响应方法
        private void showMessage(object sender, CostomEventArgs e)
        {
            Console.WriteLine(e.Message);
        }

        public void OnClick(object sender, CostomEventArgs eventArgs)
        {
            showMessage(sender, eventArgs);
        }
        public void OnDoubleClick(object sender, CostomEventArgs eventArgs)
        {
            showMessage(sender, eventArgs);
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            CostomEventPublisher cep = new CostomEventPublisher();
            CostomEventListener cel = new CostomEventListener(cep);
            cep.FireClick("Hello");
            cep.FireDoubleClick("Word");
            Console.ReadLine();
        }
    }

    //自定义事件参数
    internal sealed class CostomEventArgs : EventArgs
    {
        private readonly string message;

        public string Message
        {
            get { return message; }
        }

        public CostomEventArgs(string message)
        {
            this.message = message;
        }
    }

    //定义事件发布者
    internal class CostomEventPublisher
    {
        EventHandlerList eventList;
        static object eventClickKey = new object();//使用预分配静态变量作为键,以减少托管堆压力。
        static object eventDoubleClickKey = new object();

        public CostomEventPublisher()
        {
            eventList = new EventHandlerList();
        }

        //定义事件
        public event EventHandler<CostomEventArgs> Click
        {
            add
            {
                eventList.AddHandler(eventClickKey, value);
            }
            remove
            {
                eventList.RemoveHandler(eventClickKey, value);
            }
        }
        public event EventHandler<CostomEventArgs> DoubleClick
        {
            add
            {
                eventList.AddHandler(eventDoubleClickKey, value);
            }
            remove
            {
                eventList.RemoveHandler(eventDoubleClickKey, value);
            }
        }

        //引发事件
        protected virtual void OnEvent<T>(T e, EventHandler<T> eventDelegate) where T : EventArgs
        {
            e.Raise(this, ref eventDelegate, false);
        }

        //构造参数实例,并引发事件
        public void FireClick(string message)
        {
            CostomEventArgs e = new CostomEventArgs("Click:" + message);
            OnEvent(e, eventList[eventClickKey] as EventHandler<CostomEventArgs>);
        }

        public void FireDoubleClick(string message)
        {
            CostomEventArgs e = new CostomEventArgs("Double:" + message);
            OnEvent(e, eventList[eventDoubleClickKey] as EventHandler<CostomEventArgs>);
        }
    }

    //扩展方法封装线程安全逻辑
    public static class EventArgExtensions
    {
        public static void Raise<T>(this T e, Object sender, ref EventHandler<T> eventDelegate, bool ifIgnoreException) where T : EventArgs
        {
            EventHandler<T> temp = Interlocked.CompareExchange(ref eventDelegate, null, null);
            if (temp != null)
            {
                if (!ifIgnoreException)
                {
                    try
                    {
                        temp(sender, e);
                    }
                    catch
                    {
                        //TODO:处理异常
                    }
                }
                else
                {
                    Delegate[] delegates = temp.GetInvocationList();
                    foreach (Delegate del in delegates)
                    {
                        try
                        {
                            temp(sender, e);
                        }
                        catch
                        { }
                    }
                }
            }
        }
    }

    //定义监听者
    internal sealed class CostomEventListener
    {
        //添加事件监听
        public CostomEventListener(CostomEventPublisher costomEventManager)
        {
            costomEventManager.Click += showMessage;
            costomEventManager.DoubleClick += showMessage;
        }

        //响应方法
        private void showMessage(object sender, CostomEventArgs e)
        {
            Console.WriteLine(e.Message);
        }

        //移除事件监听
        public void Unregister(CostomEventPublisher costomEventManager)
        {
            costomEventManager.Click -= showMessage;
            costomEventManager.DoubleClick -= showMessage;
        }
    }
}
  • 艺术可以挂号对事件的关爱。
  • 办法可以裁撤对事件的关心。
  • 事件发送时,关注该事件的方法会收到文告。

  还索要专注的是线程安全,上例给出了一种线程安全的轩然大波引发代码。考虑线程竟态条件应该发现到的一个生死攸关是,一个艺术可能在事件的信托列表中移除之后收获调用。

  事件是一个类为委托的字段再加上三个对字段举办操作的措施。事件是寄托列表头部的引用,是为着简化和立异使用委托来作为应用程序的回调机制时的编码。.NET事件援助倚重于委托,以下代码显示了在未使用事件时的编码:

  假使类型定义了事件,那么类型(或项目实例)就足以通知其他对象发送了一定的政工。假如定义了风波成员,这样类型要提供以下能力:

1 事件的宏图

(四) 常量与字段的筹划

  • 不要提供公有的或受保障的实例字段,应该一味把字段定义为private。
  • 要用常量字段来代表永远不会变动的常量。
  • 要用公有的静态只读字段定义预定义的靶子实例。
  • 毫无把可变类型的实例赋值给只读字段。

图片 1

  • 要用System.伊夫(Eve)ntHandler<T>来定义事件处理函数,而不是手工成立新的寄托来定义事件处理函数。
  • 设想用伊芙(Eve)ntArgs的子类来做事件的参数,除非整套确信该事件不需要给事件处理方法传递任何数据,在这种场合下得以直接行使伊夫ntArgs。
  • 要用受保障的虚方法来触发事件,一般方法以名字“On”起先,随后是事件名字。该规则只适用于非密封类中的非静态事件,不适用于社团、密封类及静态事件。派生类在覆盖虚方法时能够不调用基类的实现,要准备好应对这种情形,不要在该措施中做此外对基类来说不可或缺的处理。
  • 即便类中有一个风波,那么在调用委托往日需要加一个非空测试,其代码形如:“ClickHandler
    handler=Click;if(handler !=null) handler(this,e);”。
  • 编译器生成的用来增长和删除事件处理方法的代码在多线程中不安全,所以一旦需要援助让多线程同时添加或删除事件处理方法,那么需要协调编辑代码来增长和去除事件处理方法,并在内部开展锁操作。
  • 要让触发事件的受保障办法带一个参数,该参数的类别为事件参数类,该参数的名字应该为“e”。
  • 并非在触发非静态事件时把null作为sender参数传入。
  • 要在触发静态事件时把null作为sender参数传入。
  • 永不在触及事件时把null作为数据参数传入,假设这多少个传任何数据应该接纳伊芙ntArgs.Empty。
  • 设想动用Cancel伊芙ntArgs或它的子类作为参数,来触发可以被最后用户废除的风波,这只适应于前置事件。代码形如:“void
    科尔ingHandler(object
    sender,Cancel伊芙(Eve)ntArgse){ e.Cancel=true;}”。

  尽管委托讲明可以定义任何方法签名,但在实践中事件委托应该符合一些一定的指引方针,首要概括:

2 自定义处理函数的设计

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            CostomEventPublisher cep = new CostomEventPublisher();
            CostomEventListener cel = new CostomEventListener(cep);
            cep.FireEvent("Hello");
            cep.FireEvent("Word");
            Console.ReadLine();
        }
    }

    //自定义事件参数
    internal sealed class CostomEventArgs : EventArgs
    {
        private readonly string message;

        public string Message
        {
            get { return message; }
        }

        public CostomEventArgs(string message)
        {
            this.message = message;
        }
    }

    //定义事件发布者
    internal class CostomEventPublisher
    {
        //定义事件
        public event EventHandler<CostomEventArgs> CostomEvent;

        //引发事件
        protected virtual void OnCostomEvent(CostomEventArgs e)
        {
            e.Raise(this, ref CostomEvent, false);
        }

        //构造参数实例,并引发事件
        public void FireEvent(string message)
        {
            CostomEventArgs e = new CostomEventArgs(message);
            OnCostomEvent(e);
        }
    }

    //扩展方法封装线程安全逻辑
    public static class EventArgExtensions
    {
        public static void Raise<T>(this T e, Object sender, ref EventHandler<T> eventDelegate, bool ifIgnoreException) where T : EventArgs
        {
            EventHandler<T> temp = Interlocked.CompareExchange(ref eventDelegate, null, null);
            if (temp != null)
            {
                if (!ifIgnoreException)
                {
                    try
                    {
                        temp(sender, e);
                    }
                    catch
                    {
                        //TODO:处理异常
                    }
                }
                else
                {
                    Delegate[] delegates = temp.GetInvocationList();
                    foreach (Delegate del in delegates)
                    {
                        try
                        {
                            temp(sender, e);
                        }
                        catch
                        { }
                    }
                }
            }
        }
    }

    //定义监听者
    internal sealed class CostomEventListener
    {
        //添加事件监听
        public CostomEventListener(CostomEventPublisher costomEventManager)
        {
            costomEventManager.CostomEvent += showMessage;
        }

        //响应方法
        private void showMessage(object sender, CostomEventArgs e)
        {
            Console.WriteLine(e.Message);
        }

        //移除事件监听
        public void Unregister(CostomEventPublisher costomEventManager)
        {
            costomEventManager.CostomEvent -= showMessage;
        }
    }
}

图片 2

(六).NET松耦合事件

  假设字段是援引类型,且被标记为readonly,那么不可更改的是引用,而非字段引用的靶子。

1 事件访问器

  • 把事件处理函数的回到值类型定义为void。
  • 要用object作为事件处理函数的率先个参数的项目,并将其命名为sender。
  • 要用伊芙ntArgs或其子类作为事件处理函数的第二个参数的档次,并将其取名为e。
  • 无须在事件处理函数中运用六个以上的参数。

(三) 常量与只读字段的分别

第四步 防御式发布事件

  类应定义一个受保障的虚方法。要掀起轩然大波时,当前类及其派生类中的代码会调用该情势。

  我们在上例中看看的事件的全体定义会转换为以下3个社团:

  • 首先,目的措施的回来类型应为void。使用void的缘由是,向事件宣布者再次来到一个值毫无意义,发布者不知道事件订阅者为何要订阅,另外,委托类向发表者隐藏了实在宣布操作。该信托对其内部接收器列表举办遍历(订阅对象),调用每个对应的不二法门,由此回到的值不会传来到发表者的代码。使用void重回类型还提议我们避免使用含有ref或out参数修饰符的出口参数,因为各类订阅者的输出参数不会传出给发表者。
  • 其次,一些订阅者可能想要从两个事件发表源接收相同的事件。为了让订阅者区分出不同的发布者触发的风波,签名应涵盖发表者的标识。在不依靠泛型的情景下,最简易的办法就是充足一个object类型的参数,称为发送者(sender)参数。之所以要求sender参数是object类型,重假若出于后续。另一个缘由是世故。它同意委托由三个门类应用,只有那多少个项目提供了一个会传送相应的轩然大波参数的轩然大波。
  • 终极,定义实际事件参数将订阅者与发布者耦合起来,因为订阅者需要一组特定的参数。.NET提供了伊芙(Eve)ntArgs类,作为正式是事件参数容器。

  这段代码是概念事件的一种缩写形式,它会隐式定义添加和删除处理程序的不二法门并申明委托的一个变量。当编译器编译这段代码时,会把它转换为以下3个布局:

一 常量与字段

  处理大量风波的问题在于,为每个事件都分配一个类成员是不具体的。为釜底抽薪此题材,.NET提供了伊芙ntHandlerList类。伊芙ntHandlerList是存储键/值对的线性列表。键是标识事件的对象,值是Delegate的实例。因为索引是一个对象,所以它可以是整数、字符串、特定的按钮实例等等。使用AddHandler和RemoveHandler方法可以独家增长和删除各样事件处理方法。还足以拔取AddHandlers()方法添加现有伊夫(Eve)ntHandlerList的情节。要接触事件,用带键值对象的索引器来拜访事件列表,得到一个Delegate对象。将该为她转换为实在事件委托,然后触发事件。实例代码如下:

  在.NET中,假设委托在其内部列表中尚无对象,它的值将安装为null。C#发表者在尝试调用委托在此之前,应该检查该信托是否为null,以判断是否有订阅者订阅事件。

(一) 常量


常量与字段

  • 对此每个要从里边接收事件的发表者对象,订阅者都必须重新添加订阅的代码,没有一种格局可以订阅某个项目标事件并使该事件传递给订阅者,而不论宣布者是什么人。
  • 订阅者不能筛选已接触是事件(例如,指示“仅在满意某种条件是才通告我该事件”)。
  • 订阅者必须有某种形式拿到发布者对象才能对其进展订阅,这样就导致了订阅者和发表者之间以及各种订阅者之间的耦合。
  • 宣布者和订阅者具有耦合的生命周期,两者必须同时运转。订阅者无法通知.NET“假设其余对象触发此事件,请创制一个自我的实例,并由自己来处理”。
  • 尚无捷径执行废除订阅操作,公布者对象在脱机是电脑上接触事件,一旦统计机处于联机状态,该事件便会传给订阅者。反之,订阅者运行在脱机的处理器上,一旦处于联机状态,接收到在断开连接时接触是事件也是唯恐的。
  • 订阅的确立和撤回必须经过编程情势完成。


事件

  .NET事件简化了风波管理,它使我们不用去写管理订阅者列表的繁琐的代码。然则遵照委托的事件仍旧存在以下缺陷:

其次步 定义委托签名


事件

  通过隐蔽实际事件成员,事件访问器提供了迟早水平的包裹。这还不够,通过编制订阅者接口进一步封装。实例代码如下:

  另一个索要专注的题目是非凡。所有未处理的订阅者引发的相当都会流传给发表者,导致宣布者崩溃。所以,使用时最好在try/catch块内部发布事件。

(一) 怎么着行使事件

  事件访问器类似于属性,在容易使用的还要隐藏了实在类成员。

  类型之所以能提供事件通报功效,是因为品种维护了一个已登记方法的列表,事件发送后,类型会通告列表中具有办法。

   style=”font-size: 12px;”>//1 一个被初阶化为null的私家委托字段

style=”font-size: 12px;”>  private EventHandler<CostomEventArgs>
CostomEvent = null;

 

  //2
一个公共add_xxx方法(xxx代表事件名),用于添加事件订阅

  public void
add_CostomEvent(EventHandler<CostomEventArgs> value)

  {

style=”font-size: 12px;”>    EventHandler<CostomEventArgs>
prevHandler;

style=”font-size: 12px;”>    EventHandler<CostomEventArgs> costomEvent
=this.CostomEvent ;

    do

    {

      prevHandler=costomEvent
;

style=”font-size: 12px;”>      EventHandler<CostomEventArgs>
newHandler=(EventHandler<CostomEventArgs>)Delegate.Combine(prevHandler,value);

      costom伊夫(Eve)nt
=Interlocked.CompareExchange<伊夫(Eve)ntHandler<Costom伊芙ntArgs>>(ref
this.Costom伊夫(Eve)nt,newHandler,prevHandler);//通过轮回和对CompareExchange的调用,可以以一种线程安全的办法向事件添加一个信托。

    }

    while(costomEvent
!= prevHandler);

  }

  

  //3
一个公共remove_xxx方法,用于撤消事件订阅

  public void
remove_CostomEvent(EventHandler<CostomEventArgs> value)

  {

style=”font-size: 12px;”>    EventHandler<CostomEventArgs>
prevHandler;

style=”font-size: 12px;”>    EventHandler<CostomEventArgs> costomEvent
=this.CostomEvent ;

    do

    {

      prevHandler=costomEvent
;

style=”font-size: 12px;”>      EventHandler<CostomEventArgs>
newHandler=(EventHandler<CostomEventArgs>)Delegate.Remove(prevHandler,value);

      costom伊夫(Eve)nt
=Interlocked.CompareExchange<伊夫(Eve)ntHandler<Costom伊芙(Eve)ntArgs>>(ref
this.Costom伊芙(Eve)nt,newHandler,prevHandler);//通过巡回和对CompareExchange的调用,可以以一种线程安全的法子向事件移除一个信托。

    }

    while(costomEvent
!= prevHandler);

  }

目录

相关文章