Unity3d-C#之Delegate和Event疑惑?

来源:互联网 发布:撮合交易 算法 编辑:程序博客网 时间:2024/05/22 00:32

1.如果多次注册同一个事件处理函数时,触发时处理函数是否也会多次触发?

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace TestCSharp{    class Animation    {        public delegate void PlayHandler();        public event PlayHandler Callback;        public Animation()        {            this.Callback += Move;            this.Callback += Move;            this.Callback += Move;            this.Callback();        }        public void Move()        {            Console.WriteLine("Move");        }        public void Run()        {            Console.WriteLine("Run");        }        public void Jump()        {            Console.WriteLine("Jump");        }    }}


可以注册多次同一个函数,触发时会如上图所示执行多次.


2.如果注册了一个事件处理函数,却执行了两次或多次”注销事件“,是否会报错?

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace TestCSharp{    class Animation    {        public delegate void PlayHandler();        public event PlayHandler Callback;        public Animation()        {            this.Callback += Move;            this.Callback -= Move;            this.Callback -= Move;            this.Callback();        }        public void Move()        {            Console.WriteLine("Move");        }        public void Run()        {            Console.WriteLine("Run");        }        public void Jump()        {            Console.WriteLine("Jump");        }    }}

注册一次,可以注销多次,但是要注意触发时要检查是否为空,做如下修改后避免如上图的空指针异常

            if (this.Callback != null)            {                this.Callback();            }

3.如何认定两个事件处理函数是一样的? 如果是匿名函数呢?

using System.Text;namespace TestCSharp{    class Animation    {        public delegate void PlayHandler();        public event PlayHandler Callback;        public Animation()        {            this.Callback += ()=> Console.WriteLine("Jump");            //Event Unsubscription Via Anonymous Delegate            this.Callback -= () => Console.WriteLine("Jump");        }    }}

Resharper给出提示Event Unsubscription Via Anonymous Delegate,看起来一致的匿名函数,实际上方法签名是不一样,所以不能如上代码所示取消订阅一个匿名方法。如下代码给出如何取消订阅匿名方法的解决方案。

using System.Text;namespace TestCSharp{    class Animation    {        public delegate void PlayHandler();        public event PlayHandler Callback;        public Animation()        {            PlayHandler func = () => Console.WriteLine("Jump");            this.Callback += func;            this.Callback -= func;            this.Callback += func;            this.Callback();        }    }}

更多取消匿名事件的资料参见官方文档:http://msdn.microsoft.com/en-us/library/ms366768.aspx


4.如果不手动注销事件函数,系统会帮我们回收吗?

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace TestCSharp{    class EventSource    {        public delegate void PlayHandler();        public event PlayHandler Callback;        public void Excute()        {            if (this.Callback != null)            {                this.Callback();            }        }    }}

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace TestCSharp{    class Listener    {        public Listener(EventSource source)        {            source.Callback += Run;        }        private void Run()        {            Console.WriteLine("Run");        }        ~Listener()        {            Console.WriteLine("Listener 销毁");        }    }}
using System;using System.Collections;using System.Collections.Generic;namespace TestCSharp{     class MainClass    {        public static void Main(string[] args)        {            EventSource s = new EventSource();            Listener l = new Listener(s);            s.Excute();            l = null;            Gc();            s.Excute();            s = null;            Gc();        }        public static void Gc()        {            Console.WriteLine("GC 开始");            GC.Collect();            GC.WaitForPendingFinalizers();            GC.Collect();            Console.WriteLine("GC 结束");        }    }   }

注意第二次调用s.Excute()前,已将listener赋为null,并执行Gc,但是仍然输出Run。直到将source赋为null时,listener才被回收掉。
下面我们手工注销事件,看看系统能不能自动回收?

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace TestCSharp{    class Listener    {        public Listener(EventSource source)        {            source.Callback += Run;        }        //添加一个手工注销方法        public void DeregisterEvent(EventSource source)        {            source.Callback -= Run;        }         private void Run()        {            Console.WriteLine("Run");        }        ~Listener()        {            Console.WriteLine("Listener 销毁");        }    }}

using System;using System.Collections;using System.Collections.Generic;namespace TestCSharp{     class MainClass    {        public static void Main(string[] args)        {            EventSource s = new EventSource();            Listener l = new Listener(s);            s.Excute();            //手工调用注销            l.DeregisterEvent(s);            l = null;            Gc();            s.Excute();            s = null;            Gc();        }        public static void Gc()        {            Console.WriteLine("GC 开始");            GC.Collect();            GC.WaitForPendingFinalizers();            GC.Collect();            Console.WriteLine("GC 结束");        }    }   }


这次我们可以看到run执行一次,listener也早早的被回收了。

更多系统回收资料参见:http://www.codeproject.com/Articles/29922/Weak-Events-in-C




0 0
原创粉丝点击