C# Event在.Net規則下由接口定義的實現

最近在學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

相關文章
相關標籤/搜索