国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

《C#高級編程》之委托學習筆記 (轉載)

2019-11-17 02:14:25
字體:
來源:轉載
供稿:網友

《C#高級編程》之委托學習筆記 (轉載)

全文摘自

http://www.survivalescaperooms.com/xun126/archive/2010/12/30/1921551.html

寫得不錯,特意備份!并改正其中的錯誤代碼..

正文:

最近在學C#的委托,通過網絡的資料和書籍,現在總結如下:

回調(Callback)函數是windows編程的一個重要部分。回調函數實際上是方法調用的指針,也成為函數指針,是一個非常強大的編程特

回調(Callback)函數是windows編程的一個重要部分。回調函數實際上是方法調用的指針,也成為函數指針,是一個非常強大的編程特性。.NET以委托的形式實現了函數的指針的概念。與C/C++的函數指針不同的是.NET委托是類型安全的。也就是說C/C++的函數指針只不過是一個指向內存單元的指針,我們無法知道這個指針實際指向什么,像參數和返回類型等就無從知曉了。

當把方法傳送給其他方法時,需要用到委托。如考慮以下的函數:

  C++:

    #include <iostream>

    #include <string>

    using namespace std;

    int fun(int);

    int fun_call(int (*f)(int),int);

    void main(int argc,char* argv[])

    {

        typedef int (*fp)(int);

        fp fpt;

        fpt=fun;

        count<<fun_call(fpt,1);

    }

    int fun(int a)

    {

        return a-1;

    }

    int fun_call(int (*fp)(int),int b)

    {

        return (fp(10)+b);

    }

  上述程序的“ftp=fun”實現函數指針的初始化,直接將fun的地址賦給函數指針ftp,然后傳送給fun_call,fun_call可以根據這兩個參數計算出結果:fp(10)=9,9+1=10。實現了把方法傳送給其他方法。

  函數指針最常用的是使用函數指針數組來批量調用函數:

      int f1(){return 1;}

     int f2(){return 2;}

      int f3(){return 3;}

    void main(int argc,char* argv[])

      {

        tpyedef int (* fp)();

        fp fps[3]={f1,f2,f3};

        for(int 0;i<2;i++)

        {

          cout<<fps[i]<<endl;    //實現按數組序列號調用函數

        }

      }

  在編譯時我們不知道第二個方法會是什么,這個信息只能在運行時得到,所以需要把第二個方法作為參數傳遞給第一個方法。在C/C++,只能提取函數的地址,并傳送為一個參數。c是沒有類型安全性的,可以把任何函數傳送給需要函數指針的方法。這種直接的方法會導致一些問題,例如類型安全性,在面向對象編程中,方法很少是孤立存在的,在調用前通常需要與類實例相關聯。而這種指針的方法沒考慮這種情況。所以.NET在語法上不允許使用這種直接的方法。如果要傳遞方法,就必須把方法的細節封裝在一種新的類型的對象中,這種新的對象就是委托。

  委托,實際上只是一種特殊的對象類型,其特別之處在于,我們之前定義的所有對象都包含數據,而委托包含的只是函數的地址。

  1、在c#中聲明委托

  delegate void Method(int x);

  定義了委托就意味著告訴編譯器這種類型的委托代表了哪種類型的方法,然后創建該委托的一個或多個實例。編譯器在后臺將創建表示該委托的一個類。也就是說,定義一個委托基本上是定義一個新類,所以可以在定義類的任何地方定義委托,既可以在類的內部定義,也可以在類的外部定義。注意,委托是類型安全性非常高的,因此定義委托時,必須給出它所代表的方法簽名和返回類型等全部細節。

  2、在C#中使用委托

    using System;

    namespace DelegateSpace

    {

        class DelegateTest

        {

            PRivate delegate string GetString(int x,int y);

            static void Main()

            {

               Test test=new Test();

               GetString method=new GetString(test.Add);

               Console.WriteLine(method());

            }

        }

        class Test

        {

            public string Add(int x,int y)

            {

               return (x+y).ToString();

            }

        }

    }

    上述程序中聲明了類型為GetString的委托,并對它初始化,使它指向對象test的方法Add(int x,int y)。在C#中,委托在語法上總是帶有一個參數的構造函數,這個參數就是委托指向的方法,這個方法必須匹配最初定義委托時的簽名。如上例中委托是這樣定義的:“delegate string GetString();”要求被委托的函數的返回類型是string,如果test.Add(int x,int y)返回的是int,則編譯器就會報錯。還要注意賦值的語句:“GetString method=new GetString(test.Add);“不能寫成"GetString method=new GetString(test.Add(3,2));"因為test.Add(2,3)返回的是string。而委托的構造函數需要把傳進的是函數的地址,這很像C/C++的函數指針。

  3、多播委托

  調用委托的次數與調用方法的次數相同,如果要調用多個方法,就需要多次顯式調用這個委托。委托也可以包含多個方法。這種委托稱為多播委托。如果調用多播委托,就可以按順序連續調用多個方法。所以,委托的簽名必須返回void,否則,就只能得到委托調用的最后一個方法的結果。

  如:

    delegate void DoubleOp(double value);

    class MainEntry

    {

        static void Main()

        {

            DoubleOp Operations=MathOperation.MultiplyByTwo;

            operations+=MathOperation.Square;

        }

    }

    class MathOperation

    {

        public static double MultiplyByTwo(double value)

        {

            return value*2;

        }

        public static double Square(double value)

        {

            return value*value;

        }

    }

  上面的“DoubleOp operation=MathOperation.MultiplyByTwo;operation+=MathOperation.Square;” 等價于“DoubleOp operation1=MathOperation.MultiplyByTwo;DoubleOp operation2=MathOperation.Square;DoubleOP operations=operation1+operation2;”,多播委托還可以識別運算符-和-=,用于從委托中刪除方法調用。

  通過一個多播委托調用多個方法還有一個大問題。多播委托包含一個逐個調用委托的集合。如果通過委托調用一個方法拋出異常,整個迭代就會終止。在這種情況下,為了避免這個問題,應手動迭代方法列表。可以使用Delegate類定義的方法GetInvocationList(),它返回一個Delegate對象數組。

  如考慮以下代碼:

    public delegate void DemoDelegate();

    class Program

    {

        static void One()

        {

            Console.WriteLine("One");

            throw new Exception("Test!");

        }

        static void Two()

        {

            Console.WriteLine("Two");

        }

        static void Main()

        {

            DemoDelegate dl=One;

            dl+=Two;

            try

            {

                dl();

            }

            catch(Exception)

            {

                Console.WriteLine("Exception caught!");

            }

        }

    }

    運行結果:

    One

    Exception caught!

    修改后的代碼如下:

    static void Main()

    {

        DemoDelegate dl=One;

        dl+=Two;

        Delegate[] delegates=dl.GetInvocationList();

        foreach(DemoDelegate d in delegates)

        {

            try

            {

                d();

            }

            catch(Exception)

         {

            Console.WriteLine("Exception caught");

         }

        }

       

    }

    運行結果如下:

    One

    Exception caught

    Two

  同樣地,如果委托簽名不是返回void,但希望得到所有的經委托調用后的結果,也可以用GetInvocationList()得到Delegate對象數組,再用上面的迭代方式獲得返回結果。

  4、匿名方法

  使用委托還有另外一種方式:通過匿名方法。匿名方法是用作委托參數的一個代碼塊。

  如下代碼:

  using System;

  namespace DelegateTest

  {

    class Program

    {

        delegate string delegateString(string val);

        static void Main()

        {

            string mid=",middle part";

            delegateString anonDel=delegate(string param)

            {

                param+=mid;

                param+=" and end";

                return param;

            };

            Console.WriteLine(anonDel("Strat of string"));

        }

    }

  }

  該代碼塊使用方法級的字符串變量mid,該變量是在匿名方法的外部定義的,并添加到要傳送的參數中,接著代碼返回該字符串值。匿名方法的優點是減少要編寫的代碼。不必定義僅由委托使用的方法。在為事件定義委托時,這是很顯然的。這有助于減低代碼的復雜性,尤其是定義了好幾個事件時,代碼會顯得比較簡單。使用匿名方法時,代碼執行得不太快。

  在使用匿名方法時,必須遵循一些規則:

  1)在匿名方法中不能使用跳轉語句跳到該匿名方法的外部;

  2)匿名方法外部的跳轉語句不能跳到該匿名方法的內部;

  3)在匿名方法內部不能訪問不安全代碼,也不能訪問在匿名方法外部使用的ref和out參數,但可以使用在匿名方法外部定義的其他變量。

  5、λ表達式

  這是C# 3.0為匿名方法提供的一個新方法。如前面的語句:

  ...

  static void Main()

  {

    string mid=...;

    delegateString anonDel=param=>

    {

        param+=mid;

        param+=" and end";

        return param;

    };

    ...

  }

  ...

  λ表達式=>的左邊列出了匿名方法需要的參數,右邊列出了實現代碼,實現代碼放在花括號中,類似于前面的匿名方法,如果實現代碼只有一行,可以刪除花括號和return語句,編譯器會自動添加該語句。

  如:public delegate bool Predicate(int val);

    Predicate pl=x=>x>5;

  在上面的λ表達式中,左邊定義了變量x,這個變量的類型自動設置為int,因為這是通過委托定義的,實現代碼返回比較x>5布爾結果。如果x大于5,則返回true,否則返回false。

  6、協變和抗變

  委托調用的方法不需要與委托聲明的定義類型相同。由此出現協變和抗變。

  1)返回類型協變

  方法的返回類型可以派生于委托定義的類型。如下代碼:

    public class DelegateReturn

    {

    }

    public class DelegateReturn2:DelegateReturn

    {

    }

    public delegate DelegaReturn MyDelegate1();

    class Program

    {

        static void Main()

        {

            MyDelegate1 d1=Method1;

            d1();

        }

        static DelegateReturn2 Method1()

        {

            DelegateReturn2 d2=new DelegateReturn2();


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 筠连县| 东平县| 武义县| 涞水县| 沙坪坝区| 郑州市| 黄骅市| 丹东市| 南漳县| 敦煌市| 黄陵县| 宜宾市| 桃源县| 太和县| 磴口县| 松潘县| 中江县| 武冈市| 综艺| 滨州市| 鲁甸县| 建宁县| 井研县| 弋阳县| 连州市| 益阳市| 铜陵市| 湘潭市| 周口市| 保康县| 天气| 宁乡县| 原平市| 玛纳斯县| 临潭县| 榕江县| 静乐县| 克拉玛依市| 兴业县| 来宾市| 资溪县|