最近在学C#(教材《C# in a nutshell》很不错的说),看完delegate(委托)之后,紧接着就是event(事件)了,我的对跟.Net相关的东西并无什么兴趣(毕竟是会增长代码复杂度的玩意),但是后面没准用获得,并且讲完.Net那套定义规则以后紧接着就是“接口内定义事件如何实现”,遂想试试写例子看看。shell
.Net框架下,对于事件对应的委托有三条规则:windows
1.返回值必须为void——就是没有返回值;框架
2.参数必须有一个为object——用于转移额外信息(convey extra information),这里也能够用System.EventHandler,但其实EventHandler的说明是“没有额外信息时使用”;ide
3.名称必须以EventHandler结尾,我的很讨厌Handle这个词,难以解释这是个什么东西,别问,问就句柄,但是句柄又是个什么鬼?(windowsAPI PTSD)函数
由于没有什么C#的代码经验,因此,并不清楚接口内定义事件的具体应用场合。在不符合以上规则的状况下,ui
using System; namespace ForPractise { public delegate void MathematicFunc<T>(T e); public interface IFoo { event MathematicFunc<int> InterfaceEvent; } // if .Net use subclass of EventArgs instead of int public class Foo : IFoo { private int counter; private MathematicFunc<int> _field; // private field of delegate public event MathematicFunc<int> InterfaceEvent // explictly declare add & remove of interface IFoo { // ... there could have multiple fields add { _field += value; } remove { _field -= value; } } private void OnBraodcast(int counts) // fire events { _field?.Invoke(counts); } public int Counter { get { return counter; } set { if (counter == value) { return; } counter = value; OnBraodcast(counter); } } } class Program { static int Main() { Foo foo = new Foo(); foo.Counter = 21; foo.InterfaceEvent += Multiple; foo.InterfaceEvent += Ratio; foo.Counter = 23; foo.InterfaceEvent -= Ratio; foo.Counter = 12; foo.InterfaceEvent -= Ratio; foo.InterfaceEvent += Ratio; foo.Counter = 1; Console.Read(); return 0; } static void Multiple(int num) { Console.WriteLine("{0} multiply itself {1}", num, num * num); } static void Ratio(int num) { Console.WriteLine("{0} divide 0.1 {1}", num, num / 0.1d); } } }
以上代码中,显示定义event.add跟event.remove能够省略——非必要的(即使显式定义了,在外部也只能经过"+="跟"-="进行订阅),直接写为"public event MathematicFunc<int> interfaceEvent; // 能够加上=null"便可。this
下面则是应用.Net规则的代码,会比较肿,套用这种结构,须要额外定义System.EventArgs的子类做为参数,委托在套用泛型的时候也要多加不少东西——不过多参数就能够直接塞到EventArgs的子类里面了,也不清楚是方便了仍是糟心了。同上event的显式定义也是非必要的。spa
using System; namespace ForPractise { public class FooEventArgs : EventArgs { public int Counter { set; get; } public FooEventArgs(int count) { Counter = count; } } public delegate void MathematicEventHandler<TEArgs>(object source, TEArgs e) where TEArgs : EventArgs; // delegate follow the .Net framework three rules public interface IFoo { event MathematicEventHandler<FooEventArgs> InterfaceEvent; } public class Foo : IFoo { private int counter; private MathematicEventHandler<FooEventArgs> _field; // private field of delegate public event MathematicEventHandler<FooEventArgs> InterfaceEvent // explictly declare add & remove of interface IFoo { // ... there could have multiple fields add { _field += value; } remove { _field -= value; } } private void OnBraodcast(FooEventArgs e) // fire events { _field?.Invoke(this, e); } public int Counter { get { return counter; } set { if (counter == value) { return; } counter = value; OnBraodcast(new FooEventArgs(counter)); } } } class Program { static int Main() { Foo foo = new Foo(); foo.Counter = 21; foo.InterfaceEvent += Multiple; foo.InterfaceEvent += Ratio; foo.Counter = 23; foo.InterfaceEvent -= Ratio; foo.Counter = 12; foo.InterfaceEvent -= Ratio; foo.InterfaceEvent += Ratio; foo.Counter = 1; Console.Read(); return 0; } static void Multiple(object obj, FooEventArgs e) // will be quite clumsy for simple function methods. { Console.WriteLine("{0} multiply itself {1}", e.Counter, e.Counter * e.Counter); } static void Ratio(object obj, FooEventArgs e) { Console.WriteLine("{0} divide 0.1 {1}", e.Counter, e.Counter / 0.1d); } } }
其实MathematicEventHandler这个委托名不以EventHandler结尾依旧能够正常运行,应该是没有放到标准的.Net环境下,否则就是这只是约定俗成的命名法——就跟fire event部分的函数以On作前缀同样。code
上面的两段运行结果都是同样的,暂时没找出来差异。仍是写简单一些的好呐。orm
运行结果:
23 multiply itself 52923 divide 0.1 23012 multiply itself 1441 multiply itself 11 divide 0.1 10