久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

C#基礎(chǔ)溫習(xí): 理解委托和事件

 weijianian 2016-08-07


來源:gao-yang

鏈接:http://www.cnblogs.com/gao-yang/p/5493028.html


1.委托


委托類似于C++中的函數(shù)指針(一個指向內(nèi)存位置的指針),。委托是C#中類型安全的,可以訂閱一個或多個具有相同簽名方法的函數(shù)指針,。簡單理解,,委托是一種可以把函數(shù)當(dāng)做參數(shù)傳遞的類型。很多情況下,,某個函數(shù)需要動態(tài)地去調(diào)用某一類函數(shù),,這時候我們就在參數(shù)列表放一個委托當(dāng)做函數(shù)的占位符。在某些場景下,,使用委托來調(diào)用方法能達(dá)到減少代碼量,,實現(xiàn)某種功能的用途,。



1.1 自定義委托


聲明和執(zhí)行一個自定義委托,大致可以通過如下步驟完成:


  1.  利用關(guān)鍵字delegate聲明一個委托類型,,它必須具有和你想要傳遞的方法具有相同的參數(shù)和返回值類型,;


  2.  創(chuàng)建委托對象,并且將你想要傳遞的方法作為參數(shù)傳遞給委托對象,;


  3.  通過上面創(chuàng)建的委托對象來實現(xiàn)該委托綁定方法的調(diào)用,。


下面一段代碼,完成了一次應(yīng)用委托的演示:


 //step01:使用delegate關(guān)鍵字聲明委托

    public delegate int CalcSumDelegate(int a, int b);class Program

    {

        static void Main(string[] args)

        {

            //step03:實例化這個委托,,并引用方法

            CalcSumDelegate del = new CalcSumDelegate(CalcSum);

            //step04:調(diào)用委托

            int result = del(5, 5);

            Console.WriteLine('5+5=' + result);

        }//step02:聲明一個方法和委托類型對應(yīng)

        public static int CalcSum(int a, int b)

        {

            return a + b;

        }

    }


通過上面4個步驟,,完成了委托從聲明到調(diào)用的過程。接著,,咱也學(xué)著大神用ILSpy反編譯上面的代碼生成的程序集,。截圖如下:



(1)自定義委托繼承關(guān)系是:System.MulticastDelegate —> System.Delegate —>System.Object


(2)委托類型自動生成3個方法:BeginInvoke,、EndInvoke,、Invoke。查資料得知,,委托正是通過這3個方法在內(nèi)部實現(xiàn)調(diào)用的,。


Invoke 方法,允許委托同步調(diào)用,。上面調(diào)用委托的代碼del(5, 5)執(zhí)行時,,編譯器會自動調(diào)用 del.Invoke(5,5);


BeginInvoke 方法,,以允許委托的異步調(diào)用,。假如上述委托以異步的方式執(zhí)行,則要顯示調(diào)用dal.BeginInvoke(5,5),。


 注意:BeginInvoke 和 EndInvoke 是.Net中使用異步方式調(diào)用同步方法的兩個重要方法,,具體用法詳見微軟官方示例。


1.2 多播委托


一個委托可以引用多個方法,,包含多個方法的委托就叫多播委托,。下面通過一個示例來了解什么是多播委托:


 //step01:聲明委托類型

    public delegate void PrintDelegate();

    public class Program

    {

        public static void Main(string[] args)

        {

            //step03:實例化委托,并綁定第1個方法

            PrintDelegate del = Func1;

            //綁定第2個方法

            del += Func2;

            //綁定第3個方法

            del += Func3;

            //step04:調(diào)用委托

            del();//控制臺輸出結(jié)果:

            //調(diào)用第1個方法!

            //調(diào)用第2個方法!

            //調(diào)用第3個方法!

        }

        //step02:聲明和委托對應(yīng)簽名的3個方法

        public static void Func1()

        {

            Console.WriteLine('調(diào)用第1個方法!');

        }

        public static void Func2()

        {

            Console.WriteLine('調(diào)用第2個方法!');

        }

        public static void Func3()

        {

            Console.WriteLine('調(diào)用第3個方法!');

        }

    }


可以看出,,多播委托的聲明過程是和自定義委托一樣的,,可以理解為,多播委托就是自定義委托在實例化時通過 “+=” 符號多綁定了兩個方法,。


(1)為什么能給委托綁定多個方法呢,?


自定義委托的基類就是多播委托MulticastDelegate ,這就要看看微軟是如何對System.MulticastDelegate定義的:


MulticastDelegate 擁有一個帶有鏈接的委托列表,,該列表稱為調(diào)用列表,,它包含一個或多個元素。在調(diào)用多路廣播委托時,,將按照調(diào)用列表中的委托出現(xiàn)的順序來同步調(diào)用這些委托,。如果在該列表的執(zhí)行過程中發(fā)生錯誤,則會引發(fā)異常,。(摘自MSDN)


(2)為什么使用“+=”號就能實現(xiàn)綁定呢,?


先來看上述程序集反編譯后的調(diào)用委托的代碼:



“+=”的本質(zhì)是調(diào)用了Delegate.Combine方法,該方法將兩個委托連接在一起,,并返回合并后的委托對象,。


(3)多播委托能引用多個具有返回值的方法嘛?


答案是,,當(dāng)然能,。委托的方法可以是無返回值的,也可以是有返回值的,。不過,,對于有返回值的方法需要我們從委托列表上手動調(diào)用。否則,,就只能得到委托調(diào)用的最后一個方法的結(jié)果,。下面通過兩段代碼驗證下:


public delegate string GetStrDelegate();

    public class Program

    {

        public static void Main(string[] args)

        {

            GetStrDelegate del = Func1;

            del += Func2;

            del += Func3;

            string result = del();

            Console.WriteLine(result);

            

            //控制臺輸出結(jié)果:

        //You called me from Func3

        }

        public static string Func1()

        {

            return 'You called me from Func1!';

        }

        public static string Func2()

        {

            return 'You called me from Func2!';

        }

        public static string Func3()

        {

            return 'You called me from Func3!';

        }

    }


正確做法:利用GetInvocationList獲得委托列表上所有方法,循環(huán)依次執(zhí)行委托,,并處理委托返回值,。


public delegate string GetStrDelegate();

    public class Program

    {

        public static void Main(string[] args)

        {

            GetStrDelegate del = Func1;

            del += Func2;

            del += Func3;

            //獲取委托鏈上所有方法

            Delegate[] delList = del.GetInvocationList();

            //遍歷,分別處理每個方法的返回值

            foreach (GetStrDelegate item in delList)

            {

                //執(zhí)行當(dāng)前委托

                string result = item();

                Console.WriteLine(result);

                //控制臺輸出結(jié)果:

                //You called me from Func1

                //You called me from Func2

                //You called me from Func3

            }

            Console.ReadKey();

        }

        public static string Func1()

        {

            return 'You called me from Func1';

        }

        public static string Func2()

        {

            return 'You called me from Func2';

        }

        public static string Func3()

        {

            return 'You called me from Func3';

        }

    }


1.3 匿名方法


匿名方法是C#2.0版本引入的一個新特性,,用來簡化委托的聲明,。假如委托引用的方法只使用一次,那么就沒有必要聲明這個方法,,這時用匿名方法表示即可,。


   //step01:定義委托類型

    public delegate string ProStrDelegate(string str);

    public class Program

    {

        public static void Main(string[] args)

        {

            //step02:將匿名方法指定給委托對象

            ProStrDelegate del = delegate(string str) { return str.ToUpper(); };

            string result = del('KaSlFkaDhkjHe');

            Console.WriteLine(result);

            Console.ReadKey();

            //輸出:KASLFKAFHKJHE

        }

    }


(1)匿名方法只是C#提供的一個語法糖,方便開發(fā)人員使用,。在性能上與命名方法幾乎無異,。


(2)匿名方法通常在下面情況下使用:


  1. 委托需要指定一個臨時方法,該方法使用次數(shù)極少,;


  2. 這個方法的代碼很短,,甚至可能比方法聲明都短的情況下使用。


1.4 Lambda表達(dá)式


Lambda表達(dá)式是C#3.0版本引入的一個新特性,,它提供了完成和匿名方法相同目標(biāo)的更加簡潔的格式,。下面示例用Lambda表達(dá)式簡化上述匿名方法的例子:


public delegate string ProStrDelegate(string str);

    public class Program

    {

        public static void Main(string[] args)

        {

            //匿名委托

            //ProStrDelegate del = delegate(string str) { return str.ToUpper(); };

            //簡化1

            //ProStrDelegate del1 = (string str) =>{ return str.ToUpper(); };

            //簡化2

            //ProStrDelegate del2 = (str) =>{ return str.ToUpper(); };

            //簡化3

            ProStrDelegate del3 = str => str.ToUpper();

            string result = del3('KaSlFkaDhkjHe');

            Console.WriteLine(result);

            Console.ReadKey();

            //輸出:KASLFKAFHKJHE

        }

    }


  • 簡化1:去掉delegate關(guān)鍵字,用”=>”符號表示參數(shù)列表和方法體之間的關(guān)系,;


  • 簡化2:去掉方法的參數(shù)類型,;假如只有一個參數(shù),,參數(shù)列表小括號()也可省略;


  • 簡化3:如果方法體中的代碼塊只有一行,,可以去掉return,,去掉方法體的大括號{}。


1.5 內(nèi)置委托


上述幾種委托的使用,,都沒能離開定義委托類型這一步驟,。微軟干脆直接把定義委托這一步驟封裝好,形成三個泛型類:Action,、Func和Predicate,,這樣就省去了定義的步驟,推薦使用,。


public class Program

    {

        public static void Main(string[] args)

        {

            //Action

            Actionstring> action = delegate(string str) { Console.WriteLine('你好!' + str); };

            action('GG');

//Func

            Funcint, int, int> func = delegate(int x, int y) { return x + y; };

            Console.WriteLine('計算結(jié)果:' + func(5, 6));

//Predicate

            Predicatebool> per = delegate(bool isTrue) { return isTrue == true; };

            Console.WriteLine(per(true));

        }

    }


它們的區(qū)別如下:

  • Action委托:允許封裝的方法有多個參數(shù),,不能有返回值;


  • Func委托:允許封裝的方法有多個參數(shù),,必須有返回值,;


  • Predicate委托:允許封裝的方法有一個參數(shù),返回值必須為bool類型,。


2. 事件


委托是一種類型,,事件依賴于委托,故事件可以理解為是委托的一種特殊實例,。它和普通的委托實例有什么區(qū)別呢,?委托可以在任意位置定義和調(diào)用,但是事件只能定義在類的內(nèi)部,,只允許在當(dāng)前類中調(diào)用,。所以說,事件是一種類型安全的委托,。


2.1 定義事件


通過一個簡單的場景來演示下事件的使用:


 ///

    /// 音樂播放器

    ///

    public class MusicPlayer

    {

        //step01:定義 音樂播放結(jié)束 事件

        public event EventHandler PlayOverEvent;

        public string Name { get; set; }

        public MusicPlayer(string name)

        {

            this.Name = name;

        }

        //step02:定義一個觸發(fā)事件的方法

        public void PlaySong()

        {

            //模擬播放

            Console.WriteLine('正在播放歌曲:' + this.Name);

            for (int i = 0; i 20; i++)

            {

                Console.Write('.');

                Thread.Sleep(100);

            }

            //播放結(jié)束,,則觸發(fā)PlayOverEvent事件

            if (PlayOverEvent != null)

            {

                PlayOverEvent(this, null);

            }

        }

    }

    public class Program

    {

        static void Main(string[] args)

        {

            //創(chuàng)建音樂播放器對象

            MusicPlayer player = new MusicPlayer('自由飛翔');

            //step03:注冊事件

            player.PlayOverEvent += player_PlayOverEvent;

            //播放歌曲,結(jié)束后觸發(fā)事件

            player.PlaySong();

            Console.ReadKey();

        }

        static void player_PlayOverEvent(object sender,EventArgs e)

        {

            MusicPlayer player = sender as MusicPlayer;

            Console.WriteLine('rn{0}播完了,!', player.Name);

        }

    }


程序運(yùn)行結(jié)果:



(1)總結(jié)上面事件使用的幾個步驟:


    step01:用event關(guān)鍵字定義事件,,事件必須要依賴一個委托類型;


    step02:在類內(nèi)部定義觸發(fā)事件的方法,;


    step03:在類外部注冊事件并引發(fā)事件,。


(2)public event EventHandler PlayOverEvent


這句代碼在MusicPlayer類定義了一個事件成員PlayOverEvent,我們說事件依賴于委托,、是委托的特殊實例,,所以EventHandler肯定是一個委托類型。下面我們來驗證一下:



EventHandler是微軟封裝好的事件委托,該委托沒有返回值類型,,兩個參數(shù):sender事件源一般指的是事件所在類的實例,;TEventArgs事件參數(shù),如果有需要創(chuàng)建,,要顯示繼承System.EventArgs,。


2.2 事件的本質(zhì)


 MusicPlayer player = new MusicPlayer('自由飛翔');

            //注冊事件

            player.PlayOverEvent += player_PlayOverEvent;

            player.PlaySong();


從上面代碼我們觀察到,,事件要通過”+=”符號來注冊,。我們猜想,事件是不是像多播委托一樣通過Delegate.Combine方法可以綁定多個方法,?還是通過反編譯工具查看下:



我們看到PlayOverEvent事件內(nèi)部生成了兩個方法:add_ PlayOverEvent和remove_ PlayOverEvent,。add方法內(nèi)部調(diào)用Delegate.Combine把事件處理方法綁定到委托列表;remove方法內(nèi)部調(diào)用Delegate.Remove從委托列表上移除指定方法,。其實,,事件本質(zhì)上就是一個多播委托。


3. 參考文章


[1] Edison Chou,,http://www.cnblogs.com/edisonchou/p/4827578.html


[2] jackson0714,,http://www.cnblogs.com/jackson0714/p/5111347.html


[3] Sam Xiao, http://www.cnblogs.com/xcj26/p/3536082.html


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多