要是字段是援用类型,一旦事件爆发365体育官网

style=”font-size: large;”>在上一篇旁观他本人弹指间就悟了(续)—委托,被人狂喷。说写的太空,未有啥样内容之类的。所以计划在此处重写下, style=”font-size: large;”>但是照旧按着 style=”font-size: large;”>在此以前的方法尽量简单的写。这里大家以打篮球为例。

目录

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

       当发球的球员发生它的发球事件在此以前,其余球员必要预约这么些事件,选拔这种方法,只要出现叁个发球事件,其余球

员就能够知道。

 


常量与字段

第二步:触发事件

       当球被发生时,此时发球员对象发生贰个新事件。

 


事件

其三步:球爆发叁个事件

        
创设叁个新事件,这几个事件还应该有一部分参数,如球的相距和轨迹。这个参数作为伊芙ntArgs对象的三个实例关联到事件,然后

事件产生,全部监听目的都能博取这一个事件。一旦事件时有发生,全数订购者都会拿走通告,并做一些拍卖。

一 常量与字段

第四步:订购者获得照料   

            由于其余球员对象都预约了发球球员对象的发球事件,所以那些指标会获得文告,并先后调用他们的事件管理方法。事件处

理程序正是发出事件时订购者对象运营的秘籍,一旦发球者产生了其事件,就能够创设二个BallEventArgs对象,个中包蕴球的轨迹

和距离,进而将个对象传递到订购者的事件管理程序。

(一) 常量

第五步:各类对象处监护人件

          
未来,其余球员都会以她们协和的章程处理发球事件。但是并非相同的时间运维—他们的事件处理程序会先后获得调用,并以

Ball伊夫ntArgs对象的五个援引作为参数。     

 

  常量总是被视为静态成员,并不是实例成员。定义常量将招致创立元数据。代码援引八个常量时,编写翻译器会在概念常量的次第集的元数据中查找该符号,提取常量的值,并将值嵌入IL中。由于常量的值直接嵌入IL,所以在运营时不需求为常量分配任何内部存储器。其余,无法博取常量的地点,也无法以传递引用的主意传送常量。这个限制意味着,未有很好的跨程序集版本调节特性。因而,唯有在鲜明二个标志的值从不改变化时,才应该运用。假如期望在运维时从一个主次集中提取二个程序聚集的值,那么不该使用常量,而相应利用
readonly 字段。

上面我们深入分析下把种种部分连接起来

365体育官网 1

1.大家供给一个标示事件参数的靶子

       
要切记,Play事件(大家上边把发球事件都说成play事件)有一部分亟需引导的参数。所以大家必要贰个轻巧易行的对象来代表那一个参数。

为此,.NET
提供了二个专门的学问的类,名称叫伊夫ntArgs,不过那几个类未有别的成员。它的指标唯有贰个,便是允许将你的风浪的参数对象传

递到事件事件管理程序再说利用。
以下是事件参数类的宣示:

     public class
BallEventArgs:EventArgs

 

(二) 字段

2.接下来须求在发出事件的类中定义那一个事件

     
大家在SendPlayer类中(正是发球球员类,汗,塞尔维亚语不是太好,见谅)定义一个事变,以便别的对象订购这几个事件。

宣示如下:

      public event EventHandler
Play;

style=”font-size: large;”>event关键字背后的EventHandler不是C#的保留字,它是.NET提供的。之所以供给它,是为着告诉订购事件的对象。

style=”font-size: large;”>他们的事件管理方法应该是何等样子(有哪些的签署)

style=”font-size: large;”>即他们的事件处理程序应该有多个参数,三个参数是名称叫sender的object,另八个参数是名字为e的伊芙ntArgs援引。

  CLOdyssey帮助项目字段和实例字段。对于项目字段,用于容纳字段数据的动态内部存款和储蓄器是在档案的次序对象中分红的,而项目对象是在类型加载到八个AppDomain时创设的;对于实例字段,用于容纳字段数据的动态内部存储器则是在构造类型的贰个实例时分配的。字段化解了版本调控难点,其值存款和储蓄在内部存款和储蓄器中,独有在运营时本事获得。

3.订购类需求事件管理方法

         
订购SendPlayer的Play事件的逐一对象都亟待三个事件管理程序。其实大家已经领会事件管理程序是怎么着专门的学问的,

你拉三个Button,然后双击它,IDE就机关给您扩展一个click事件。所以Play的平地风波你看起来应当很熟谙。

          

             void 
sendPlayer_Play(object sender,EventArgs e)

style=”font-size: large;”>C#中并未法规必要事件管理程序必须按某种格局命名,可是那是一种特别专门的工作的命名约定:首先是目的引用名,

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

  如若字段是引用类型,且被标识为readonly,那么不可改变的是引用,而非字段援用的靶子。

4.逐项对象订购事件

style=”font-size: large;”>一旦确立了事件管理程序,别的球员对象急需关联他们和睦的事件管理程序。每一种对象都有和好一定的

style=”font-size: large;”>sendPlayer_Play方法,对那些事件做出分歧的响应。所以,

style=”font-size: large;”>倘使有多少个SendPlayer对象引用变量或字段,名字为sendPlayer,能够用+=操作符关联事件管理程序:

 

sendPlayer.Play+=new
EventHandler(sendPlayer_Play);

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

5.SendPlayer对象产生贰个风浪通报订购者球赛开首。

style=”font-size: large;”>既然已经创办事件,那么触发这几个事件就很轻便,只要求调用Play事件。

if(Play!=null)

Play(this,e);

style=”font-size: large;”>基本的步骤都有了,我们能够依据步骤写本人的风云了。

  readonly和const本质上都是常量,readonly是运作时常量而const是编写翻译期常量。二种常量具备以下分别:

  • 编写翻译期常量的值在编写翻译时获得,而运作时常量的值在运营时得到。
  • 两侧访谈方式分裂。编写翻译期常量的值是在指标代码中进行轮换的,而运作时常量就要运维时求值,引用运行时常量生成的IL将援用到readonly的变量,实际不是变量的值。因此,编写翻译期常量的属性越来越好,而运转时常量更为灵活。
  • 编译期常量仅援助整型、浮点型、枚举和字符串,另外值类型如DateTime是无力回天起先化编写翻译期常量的。可是,运营时常量则帮助任何项目。
  • 编写翻译期常量是静态常量,而运行时常量是实例常量,可感到品种的每一种实例贮存不一样的值。

  综上所述,除非须求在编译时期取得确切的数值以外,别的情状,都应当尽恐怕选取运转时常量。

(四) 常量与字段的准备

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


事件

365体育官网,  假若类型定义了风浪,那么类型(或项目实例)就足以通报别的对象发送了特定的事情。假使定义了风浪成员,那样类型要提供以下技能:

  • 艺术能够注册对事件的关注。
  • 办法能够裁撤对事件的钟情。
  • 事件发送时,关怀该事件的方法会收到文告。

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

(一) 如何运用事件

  下例展现了怎么着使用事件:

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;
        }
    }
}

率先步 自定义事件参数

  应该在伊夫ntArgs派生类中为事件管理程序提供参数,并将这几个参数作为类成员。委托类中遍历他的订阅者列表,将参数对象在订阅者中逐个传递。但力不可能支防守有些订阅者修改参数值,进而影响其后有所的处监护人件的订阅者。平日状态下,当这个成员在订阅者中传递时,应防卫订阅者对其展开更换,可将参数的寻访权限设置为只读,或公开那几个参数为公共成员,并应用readonly访谈修饰符,在这二种情景下,都应当在构造器中先河化那一个参数。

其次步 定义委托具名

  即便委托注明能够定义任何措施具名,但在施行中事件委托应该符合一些特定的指点宗旨,主要不外乎:

  • 首先,目的措施的回来类型应为void。使用void的由来是,向事件发布者重返二个值毫无意义,发布者不知情事件订阅者为何要订阅,其它,委托类向公布者掩盖了事实上公布操作。该信托对其内部接收器列表进行遍历(订阅对象),调用每一个对应的法子,因而回到的值不会传出到发表者的代码。使用void再次回到类型还提出大家防止选用含有ref或out参数修饰符的输出参数,因为各样订阅者的出口参数不会流传给公布者。
  • 帮助,一些订阅者恐怕想要从三个事件发表源接收一样的平地风波。为了让订阅者区分出不一致的发表者触发的事件,具名应包罗公布者的标志。在不信赖泛型的图景下,最简便的措施正是加上三个object类型的参数,称为发送者(sender)参数。之所以须要sender参数是object类型,重借使由于持续。另一个缘故是世故。它同意委托由多少个项目应用,唯有那么些连串提供了二个会传递相应的事件参数的风云。
  • 最后,定义实际事件参数将订阅者与发布者耦合起来,因为订阅者供给一组特定的参数。.NET提供了伊芙ntArgs类,作为专门的工作是事件参数容器。

其三步
定义担任吸引风浪的办法来打招呼事件的挂号

  类应定义三个受保证的虚方法。要引发平地风波时,当前类及其派生类中的代码会调用该方法。

第四步 堤防式发布事件

  在.NET中,要是委托在在那之中间列表中从不指标,它的值将设置为null。C#揭橥者在品味调用委托此前,应该检查该信托是不是为null,以判定是或不是有订阅者订阅事件。

  另贰个亟待注意的标题是至极。全部未管理的订阅者引发的不行都会传出给发表者,导致公布者崩溃。所以,使用时最佳在try/catch块内部发布事件。

  还亟需专注的是线程安全,上例给出了一种线程安全的事件引发代码。思念线程竟态条件应该开采到的一个器重是,二个主意只怕在事变的寄托列表中移除之后获得调用。

(二) 处理多量轩然大波

  管理大批量风云的难点在于,为每种事件都分配一个类成员是不现实的。为解决此主题素材,.NET提供了伊夫ntHandlerList类。EventHandlerList是存款和储蓄键/值对的线性列表。键是标志事件的靶子,值是Delegate的实例。因为索引是八个对象,所以它能够是整数、字符串、特定的按钮实例等等。使用AddHandler和RemoveHandler方法能够分级增加和删除种种事件管理方法。还足以行使AddHandlers()方法增添现成EventHandlerList的剧情。要接触事件,用带键值对象的索引器来拜会事件列表,获得二个Delegate对象。将该为她调换为实在事件委托,然后触发事件。实例代码如下:

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;
        }
    }
}

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

  通过隐敝实际事件成员,事件访谈器提供了必然程度的卷入。那还相当不足,通过编拟定阅者接口进一步封装。实例代码如下:

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);
        }
    }
}

  上边代码展现了这种办法的长处,仅透过贰次调用就足以布告全体接口,并显示了对事件类成员的一心封装。

(四) 事件的面目

  事件是三个类为委托的字段再增进五个对字段实行操作的秘籍。事件是信托列表尾部的援用,是为着简化和校正使用委托来作为应用程序的回调机制时的编码。.NET事件帮衬依赖于委托,以下代码显示了在未利用事件时的编码:

    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);
            }
        }
    }

  以上代码存在下列难点——揭橥类供给将委托成员公开为公家成员变量,那样全部参预方都能够向该信托列表增添订阅者,公共的寄托成员打破了包装,导致代码应用程序安全危机。因而为了消除该难点,并简化编码微软提交了event来细化作为事件订阅和通报使用的寄托项目。将委托成员变量定义为事件后,就算该成员为公共成员,也唯有发表类(不包蕴子类)能够出发那件事件(固然任哪个人都足以向该信托列表增多指标措施)。由发表类的开拓者来支配是不是提供三个集体措施来触发该事件。使用事件代表本来委托还或然会下滑公布者与订阅者间的松耦合,因为发表者触发事件的事体逻辑对订阅者是遮蔽的。

1 事件采访器

  事件采访器类似于属性,在轻易使用的还要隐蔽了事实上类成员。

  Costom伊夫ntReleaser中利用以下代码定义事件:

    public event
EventHandler<CostomEventArgs> CostomEvent;

  这段代码是概念事件的一种缩写情势,它会隐式定义加多和删除管理程序的秘籍并声称委托的三个变量。当编写翻译器编写翻译这段代码时,会把它转变为以下3个协会:

365体育官网 2

2 隐式达成事件

  大家在上例中见到的风浪的完好定义会调换为以下3个布局:

   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伊芙nt
=Interlocked.CompareExchange<EventHandler<Costom伊芙ntArgs>>(ref
this.CostomEvent,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伊芙nt
=Interlocked.CompareExchange<伊夫ntHandler<CostomEventArgs>>(ref
this.CostomEvent,newHandler,prevHandler);//通过轮回和对CompareExchange的调用,能够以一种线程安全的章程向事件移除二个信托。

    }

    while(costomEvent
!= prevHandler);

  }

  除了生成上述3个布局,编写翻译器还或许会在托管程序集的元数据中生成一个风浪定义纪录项。这一个记录项满含部分注解和基础委托项目,还引述了add和remove访谈器方法。这一个新闻的功效是确立“事件”的抽象概念和它的访问器方法之间的联络。编写翻译器和别的工具得以选用那么些元数据音讯,并可通过System.Reflection.EventInfo类获取这几个消息。但是,CLPAJERO本人并不应用那几个消息,它在运作时只需求访谈器方法。

(五)
事件与自定义管理函数的计划

1 事件的设计

  • 要用System.伊夫ntHandler<T>来定义事件管理函数,而不是手工业创制新的嘱托来定义事件管理函数。
  • 思虑用EventArgs的子类来做事件的参数,除非整套确信该事件无需给事件管理方法传递任何数据,在这种情景下能够直接采纳EventArgs。
  • 要用受保险的虚方法来触发事件,一般方法以名字“On”早先,随后是事件名字。该准绳只适用于非密闭类中的非静态事件,不适用于组织、密闭类及静态事件。派生类在覆盖虚方法时能够不调用基类的贯彻,要筹划好应对这种景色,不要在该方式中做别的对基类来讲不能缺少的拍卖。
  • 若果类中有一个事件,那么在调用委托在此以前要求加七个非空测验,其代码形如:“ClickHandler
    handler=Click;if(handler !=null) handler(this,e);”。
  • 编译器生成的用来丰裕和删除事件处理方法的代码在四线程中不安全,所以假设供给支持让二十八线程同一时间丰裕或删除事件管理方法,那么必要团结编写代码来丰盛和去除事件管理方法,并在内部开始展览锁操作。
  • 要让触发事件的受保证方法带贰个参数,该参数的档期的顺序为事件参数类,该参数的名字应该为“e”。
  • 并不是在触发非静态事件时把null作为sender参数字传送入。
  • 要在触发静态事件时把null作为sender参数传入。
  • 不要在接触事件时把null作为数据参数字传送入,假如那么些传任何数据应该使用EventArgs.Empty。
  • 虚拟使用CancelEventArgs或它的子类作为参数,来触发能够被最终用户打消的事件,那只适应于前置事件。代码形如:“void
    ColeingHandler(object
    sender,Cancel伊夫ntArgse){ e.Cancel=true;}”。

2 自定义管理函数的宏图

  • 把事件管理函数的回来值类型定义为void。
  • 要用object作为事件管理函数的率先个参数的花色,并将其命名称叫sender。
  • 要用EventArgs或其子类作为事件管理函数的第三个参数的品类,并将其命名称为e。
  • 决不在事件管理函数中动用多少个以上的参数。

(六).NET松耦合事件

  .NET事件简化了平地风波管理,它使大家不用去写管理订阅者列表的麻烦的代码。不过依据委托的风云只怕存在以下缺欠:

  • 对此各类要从里边接收事件的发表者对象,订阅者都必须重新扩大加订阅的代码,未有一种办法能够订阅有些项目的事件并使该事件传递给订阅者,而不管发布者是什么人。
  • 订阅者不或然筛选已接触是事件(譬如,提示“仅在满意某种条件是才通告自个儿该事件”)。
  • 订阅者必须有某种格局得到公布者对象技能对其进展订阅,那样就变成了订阅者和揭橥者之间以及各类订阅者之间的耦合。
  • 发表者和订阅者具有耦合的生命周期,两个必须同一时候运转。订阅者不能够文告.NET“借使别的对象触发那一件事件,请创制七个本身的实例,并由自个儿来管理”。
  • 从不走后门实践裁撤订阅操作,发布者对象在脱机是Computer上接触事件,一旦计算机处于联机状态,该事件便会传给订阅者。反之,订阅者运维在脱机的微管理器上,一旦处于联机状态,接收到在断开连接时接触是事件也是或然的。
  • 订阅的创设和撤回必须透过编制程序格局成就。

  .Net和其它第三方框架辅助松耦合事件,在.NET中定义松耦合事件能够参见MSDN中有关System.EnterpriseServices.ServicedComponent的连带内容。

相关文章