亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#中的委托詳解

 更新時(shí)間:2022年04月11日 16:26:10   作者:Ruby_Lu  
本文詳細(xì)講解了C#中的委托,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

如果要給方法傳遞一個(gè)方法參數(shù)時(shí),就可以使用委托。要傳遞方法,就必須把方法的細(xì)節(jié)封裝在一鐘新類型的對(duì)象中,即委托。委托是一種特殊類型的對(duì)象,其特殊之處在于,我們以前定義的所有對(duì)象都包含數(shù)據(jù),而委托只包含一個(gè)或多個(gè)方法的地址。
.NET版本中,委托指向方法的地址。在C++中,函數(shù)指針是一個(gè)指向內(nèi)存位置的指針,但它不是類型安全的。開發(fā)者無法判斷這個(gè)指針實(shí)際指向什么,像參數(shù)和返回值等項(xiàng)就更不知道了。
.NET委托是類型安全的類,它定義了返回類型和參數(shù)的類型。委托類不僅包含對(duì)方法的引用,也可以包含對(duì)多個(gè)方法的引用。

1.聲明委托

使用委托和使用類一樣,也需要經(jīng)過定義和實(shí)例化兩個(gè)步驟。首先必須定義要使用的委托,對(duì)于委托,定義它就是告訴編譯器這種類型的委托表示哪種類型的方法。然后,必須創(chuàng)建該委托的一個(gè)或多個(gè)實(shí)例才能使用。編譯器在后臺(tái)將創(chuàng)建表示該委托的一個(gè)類。
定義委托的語法:

delegate void IntMethod(int x);
//定義了一個(gè)委托IntMethod,指定該委托的每個(gè)實(shí)例都可以包含一個(gè)或多個(gè)方法的引用,引用的方法必須帶有一個(gè)int參數(shù),并返回void.

因?yàn)槎x委托基本上是定義一個(gè)新類,所以可以在定義類的任何地方定義委托。也可以在委托的定義上使用修飾符:public,private,protected等。
委托派生自基類System.MulticastDelegate,MulticastDelegate又派生自基類System.Delegate.
類有兩個(gè)不同的術(shù)語:“類”表示廣義的定義,“對(duì)象”表示;類的實(shí)例。但委托只有一個(gè)術(shù)語。在創(chuàng)建委托的實(shí)例時(shí),所創(chuàng)建的實(shí)例仍稱為委托。必須從上下文中確定委托的具體含義。

2.使用委托

定義好委托之后,就可以創(chuàng)建它的一個(gè)實(shí)例,從而用它存儲(chǔ)特定方法的細(xì)節(jié)。

delegate void IntMethod(int x);

        static void Fun(int x)
        {
            Console.WriteLine(x);
        }

        static void Main()
        {
          int x = 40;
          IntMethod intMethod = new IntMethod(Fun);
          intMethod(x);
          Console.ReadKey();

        }

委托在語法上總是接受一個(gè)參數(shù)的構(gòu)造函數(shù),這個(gè)參數(shù)就是委托引用的方法。這個(gè)方法必須匹配最初定義委托時(shí)的簽名。
使用委托實(shí)例的名稱,后面加上圓括號(hào),如果需要參數(shù)就必須在圓括號(hào)內(nèi)加上參數(shù)。
給委托實(shí)例提供圓括號(hào)和調(diào)用委托類的Invoke()方法完全相同:

  intMethod(x);
  intMethod.Invoke(x);

為了減少輸入量,只需要給委托實(shí)例傳遞方法地址的名稱就可以,這稱為委托推斷。

IntMethod intMethod = new IntMethod(Fun);
IntMethod intMethod =Fun;

委托推斷可以在需要委托實(shí)例的任何地方使用。委托推斷也可以用于事件,因?yàn)槭录谖?。(事件后面文章有介紹)
注意,使用委托可以調(diào)用任何類型對(duì)象的方法,不管是靜態(tài)方法還是實(shí)例方法。

3.使用委托數(shù)組

//先在一個(gè)類中定義兩個(gè)方法:
          class MathOperations
          {
            public static double MultiplyByTwo(double value)
            {
              return value * 2;
            }

            public static double Square(double value)
            {
              return value * value;
            }
          }
//定義一個(gè)返回double類型且?guī)в衐ouble類型參數(shù)的委托
          delegate double DoubleOp(double x);

          
          class Program
          {
            static void Main()
            {
              //實(shí)例化委托數(shù)組,和實(shí)例化類的數(shù)組一樣
              DoubleOp[] operations =
              {
                MathOperations.MultiplyByTwo,
                MathOperations.Square
              };
              
              //遍歷數(shù)組,使用數(shù)組中的每個(gè)委托實(shí)例
              for (int i = 0; i < operations.Length; i++)
              {
                Console.WriteLine("Using operations[{0}]:", i);
                //將委托實(shí)例作為參數(shù)傳遞給ProcessAndDisplayNumber方法
                ProcessAndDisplayNumber(operations[i], 2.0);
                ProcessAndDisplayNumber(operations[i], 7.94);
                ProcessAndDisplayNumber(operations[i], 1.414);
                Console.WriteLine();
              }
            }

            static void ProcessAndDisplayNumber(DoubleOp action, double value)
            {
              //在ProcessAndDisplayNumber中調(diào)用委托,執(zhí)行委托實(shí)例引用的方法
              double result = action(value);
              Console.WriteLine(
                 "Value is {0}, result of operation is {1}", value, result);
            }
          }

4.Action<T>和Func<T>委托

除了為每個(gè)參數(shù)和返回類型定義一個(gè)委托類型之外,還可以使用Action<T>和Func<T>委托。
泛型Action<T>委托表示引用一個(gè)void返回類型的方法。這個(gè)委托類存在不同的變體,可以傳遞最多16種不同的參數(shù)類型。沒有泛型參數(shù)的Action類調(diào)用沒有參數(shù)的方法。Action<in T>調(diào)用帶一個(gè)參數(shù)的方法,Action<in T1,in T2>調(diào)用帶兩個(gè)參數(shù)的方法,依次類推。
Func<T>委托允許調(diào)用帶返回類型的方法。與Action<T>類似,F(xiàn)unc<T>也存在不同的變體,可以傳遞最多16種不同的參數(shù)類型和一個(gè)返回類型。Func<out TResult>委托類型可以調(diào)用無參數(shù)且?guī)Х祷仡愋偷姆椒ā?br />下面使用Func<T>委托實(shí)現(xiàn)一個(gè)不使用委托很難編寫的一個(gè)功能:給對(duì)象數(shù)組排序,如果對(duì)象是int或string這樣值類型的對(duì)象會(huì)容易排序,如果是要排序很多自定義的類型的對(duì)象,需要編寫大量代碼。使用委托會(huì)減少代碼量。
定義包含比較方法的類:
BubbleSorter類實(shí)現(xiàn)了一個(gè)泛型方法 Sort<T>,第一個(gè)參數(shù)是要排序的對(duì)象數(shù)組,第二個(gè)是一個(gè)委托,傳遞比較兩個(gè)對(duì)象的方法。這樣可以給Sort<T>方法,傳遞自定義的比較方法。

class BubbleSorter
          {
            static public void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison)
            {
              bool swapped = true;
              do
              {
                swapped = false;
                for (int i = 0; i < sortArray.Count - 1; i++)
                {
                  //調(diào)用委托中引用的方法,比較兩個(gè)對(duì)象
                  if (comparison(sortArray[i + 1], sortArray[i]))
                  {
                    T temp = sortArray[i];
                    sortArray[i] = sortArray[i + 1];
                    sortArray[i + 1] = temp;
                    swapped = true;
                  }
                }
              } while (swapped);


            }
          }

定義自定義的一個(gè)類

class Employee
          {
            public Employee(string name, decimal salary)
            {
              this.Name = name;
              this.Salary = salary;
            }

            public string Name { get; private set; }
            public decimal Salary { get; private set; }

            public override string ToString()
            {
              return string.Format("{0}, {1:C}", Name, Salary);
            }

            public static bool CompareSalary(Employee e1, Employee e2)
            {
              return e1.Salary < e2.Salary;
            }
          }

客戶端代碼:

Employee[] employees =
          {
            new Employee("Bugs Bunny", 20000),
            new Employee("Elmer Fudd", 10000),
            new Employee("Daffy Duck", 25000),
            new Employee("Wile Coyote", 1000000.38m),
            new Employee("Foghorn Leghorn", 23000),
            new Employee("RoadRunner", 50000)
          };
            //Sort執(zhí)行了自定義的Employee.CompareSalary方法
          BubbleSorter.Sort(employees, Employee.CompareSalary);

          foreach (var employee in employees)
          {
            Console.WriteLine(employee);
          }

5.多播委托

前面介紹的每個(gè)委托只包含一個(gè)方法的調(diào)用,委托也可以包含多個(gè)方法。這種委托稱為多播委托。
如果調(diào)用多播委托,就可以按順序調(diào)用多個(gè)方法,但如果委托的簽名不是返回void,就只能得到委托調(diào)用的最后一個(gè)方法的結(jié)果。
使用+=添加方法,-=刪除方法。

static void Main()
        {
          Action<double> operations = MathOperations.MultiplyByTwo;
          operations += MathOperations.Square;

          ProcessAndDisplayNumber(operations, 2.0);
          ProcessAndDisplayNumber(operations, 7.0);
          Console.WriteLine();
        }

        static void ProcessAndDisplayNumber(Action<double> action, double value)
        {
          Console.WriteLine();
          Console.WriteLine("ProcessAndDisplayNumber called with value = {0}", value);
          action(value);

        }
    
    
        class MathOperations
          {
            public static void MultiplyByTwo(double value)
            {
              double result = value * 2;
              Console.WriteLine("Multiplying by 2: {0} gives {1}", value, result);
            }

            public static void Square(double value)
            {
              double result = value * value;
              Console.WriteLine("Squaring: {0} gives {1}", value, result);
            }
          }

每次調(diào)用ProcessAndDisplayNumber方法,都會(huì)按順序調(diào)用action委托實(shí)例中的兩個(gè)方法。
輸出:

  ProcessAndDisplayNumber called with value = 2
  Multiplying by 2: 2 gives 4
  Squaring: 2 gives 4

  ProcessAndDisplayNumber called with value = 7
  Multiplying by 2: 7 gives 14
  Squaring: 7 gives 49

委托還可以使用+,-運(yùn)算符:

  Action<double> operations1 = MathOperations.MultiplyByTwo;
  Action<double> operations2 = MathOperations.Square;
  Action<double> operations = operations1 + operations2;
  operations = operations - operations2;

多播委托包含一個(gè)逐個(gè)調(diào)用的委托集合。如果其中一個(gè)方法拋出異常,整個(gè)迭代就會(huì)停止。

  static void One()
  {
    Console.WriteLine("One");
    throw new Exception("Error in one");
  }

  static void Two()
  {
    Console.WriteLine("Two");
  }

  static void Main()
  {
    Action d1 = One;
    d1 += Two;

    try
    {
      d1();
    }
    catch (Exception)
    {
      Console.WriteLine("Exception caught");
    }
  }

委托只調(diào)用了第一個(gè)方法。因?yàn)榈谝粋€(gè)方法拋出異常,委托的迭代停止,不再調(diào)用Two()方法。
避免這個(gè)問題,可以使用Delegate類定義的GetInvocationList()方法,它返回一個(gè)Delegate對(duì)象數(shù)組:

  Action d1 = One;
  d1 += Two;

  Delegate[] delegates = d1.GetInvocationList();
  foreach (Action d in delegates)
  {
    try
    {
      d();
    }
    catch (Exception)
    {
      Console.WriteLine("Exception caught");
    }
  }

輸出:

  One
  Exception caught
  Two

使用GetInvocationList()方法可以為委托的每個(gè)方法傳遞不同的參數(shù),獲取每個(gè)方法的返回值。

  static int One(int x)
  {
    return x;
  }

  static int Two(int x)
  {
    return x;
  }


  static void Main()
  {

    Func<int,int> d1 = One;
    d1 += Two;

    Delegate[] delegates = d1.GetInvocationList();
    Func<int, int> d2 = (Func<int, int>)delegates[0];
    Console.WriteLine( d2(1));

    Func<int, int> d3 = (Func<int, int>)delegates[1];
    Console.WriteLine(d3(2));

    Console.ReadKey();
  }

輸出:

  1
  2

6.匿名方法

使用匿名方法可以將方法體直接賦給委托實(shí)例,而不需要定義一個(gè)方法。

  static void Main()
  {
    string mid = ", middle part,";

    Func<string, string> anonDel = delegate(string param)
    {
      param += mid;
      param += " and this was added to the string.";
      return param;
    };
    Console.WriteLine(anonDel("Start of string"));

  }

上面代碼不是把方法名賦給委托變量anonDel,而是一段代碼,它前面是關(guān)鍵字delegate和參數(shù)列表。在使用匿名方法時(shí),可以使用外部變量。
匿名方法的優(yōu)點(diǎn)是減少了代碼量。使用匿名方法,代碼執(zhí)行速度并沒有加快。編譯器仍定義了一個(gè)方法,該方法只有一個(gè)自動(dòng)指定的名稱。
使用匿名方法,必須遵守兩條規(guī)則:

  • (1).在匿名方法中不能使用跳轉(zhuǎn)語句(break,goto,continue)調(diào)到匿名方法的外部,外部的代碼也不能調(diào)到匿名方法內(nèi)部。
  • (2).匿名方法內(nèi)部不能訪問不安全的代碼。也不能在匿名方法使用ref和out

如果需要匿名方法多次編寫同一個(gè)功能時(shí),就不要用匿名方法了。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C#多線程處理多個(gè)隊(duì)列數(shù)據(jù)的方法

    C#多線程處理多個(gè)隊(duì)列數(shù)據(jù)的方法

    本文將結(jié)合實(shí)例代碼,介紹C#多線程處理多個(gè)隊(duì)列數(shù)據(jù)的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • 詳解C#枚舉中使用Flags特性

    詳解C#枚舉中使用Flags特性

    這篇文章主要介紹了C#枚舉中使用Flags特性的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • C#實(shí)現(xiàn)給DataGrid單元行添加雙擊事件的方法

    C#實(shí)現(xiàn)給DataGrid單元行添加雙擊事件的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)給DataGrid單元行添加雙擊事件的方法,較為詳細(xì)的分析了C#給DataGrid單元添加雙擊事件的步驟及相關(guān)實(shí)現(xiàn)代碼,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • C#中DateTime日期類型格式化顯示方法匯總

    C#中DateTime日期類型格式化顯示方法匯總

    這篇文章主要介紹了C#中DateTime日期類型格式化顯示方法匯總
    2014-07-07
  • C#開發(fā)Winform實(shí)現(xiàn)學(xué)生管理系統(tǒng)

    C#開發(fā)Winform實(shí)現(xiàn)學(xué)生管理系統(tǒng)

    這篇文章介紹了C#開發(fā)Winform實(shí)現(xiàn)學(xué)生管理系統(tǒng)的項(xiàng)目案例,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • C# SESSION丟失問題的解決辦法

    C# SESSION丟失問題的解決辦法

    這篇文章主要為大家詳細(xì)介紹了C# SESSION丟失問題的解決辦法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • C#反序列化到類的實(shí)現(xiàn)方法

    C#反序列化到類的實(shí)現(xiàn)方法

    這篇文章主要介紹了C#反序列化到類的實(shí)現(xiàn)方法,涉及C#反序列化的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • C#中如何生成安裝包

    C#中如何生成安裝包

    這篇文章主要介紹了C#中如何生成安裝包問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 基于C#實(shí)現(xiàn)宿舍管理系統(tǒng)

    基于C#實(shí)現(xiàn)宿舍管理系統(tǒng)

    這篇文章主要介紹了如何利用C#語言開發(fā)一個(gè)簡易的宿舍管理系統(tǒng),文中的實(shí)現(xiàn)步驟講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定參考價(jià)值,感興趣的可以了解一下
    2022-06-06
  • C#實(shí)現(xiàn)獲取mp3 Tag信息的方法

    C#實(shí)現(xiàn)獲取mp3 Tag信息的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)獲取mp3 Tag信息的方法,涉及C#針對(duì)MP3文件屬性的相關(guān)操作技巧,需要的朋友可以參考下
    2017-07-07

最新評(píng)論