C# 委託

來源:互聯網
上載者:User

標籤:run   功能   一個   問題   加速   employee   false   opera   compare   

委託
  • 如果我們要把方法當做參數來傳遞,就用到委託,簡單來說,委託是一個類型,這個類型可以賦值一個方法的引用。
聲明委託
  • 在c#中使用一個類分兩個階段,首先定義這個類,告訴編輯器這個類由什麼欄位和方法組成,然後使用這個類執行個體化對象。在我們使用委託的時候,也需要經過這兩個階段,首先定義委託,告訴編輯器我們這個委託可以指向那些類型的方法,然後,建立該委託的執行個體。

  • 定義委託的方法如下:

    • delegate void IntMethodInvoker(int x);

    • 定義一個委託:IntMethodInvoker,這個委託可以指向什麼類型的方法?

    • 這個方法要帶有一個 int類型的參數,並且方法的傳回值是void,定義一個委託要定義方法的參數和傳回值,使用關鍵字delegate定義。

  • 定義案例:

    • delegate double TwoLongOp(long frist, long second);
    • delegate string GetAString();
委託使用
private delegate string GetAString();static void Main(){int x = 40;GetAString firstStringMethod = new GetAString(x.ToString);Console.WriteLine(firstStringMethod());}

  

  • 在這裡我們首先使用GetAString委託聲明了一個類型叫做fristStringMethod,接下來使用new 對它進行初始化,使它引用到x中的ToString方法上,這樣firstStringMethod就相當於x.ToString,我們通過firstStringMethod()執行方法就相當於x.ToString()

  • 通過委託樣本調用方法有兩種方式:

    • fristStringMethod();
    • firstStringMethod.Invoke();
委託的賦值
  • GetAString firstStringMethod = new GetAString(x.ToString);
  • 只需要把方法名給一個委託的構造方法就可以了 GetAString firstStringMethod = x.ToString;
  • 也可以把方法名直接給委託的執行個體
簡單委託樣本
  • 定義一個類MathsOperations裡面有兩個靜態方法,使用委託調用該方法
class MathOperations{public static double MultiplyByTwo(double value){return value*2;}public static double Square(double value){return value*value;}}delegate double DoubleOp(double x);static void Main(){DoubleOp[] operations={ MathOperations.MultiplyByTwo,MathOperations.Square };for(int i =0;i<operations.Length;i++){Console.WriteLine("Using operations "+i);ProcessAndDisplayNumber( operations[i],2.0 );}}static void ProcessAndDisplayNumber(DoubleOp action,double value){double res = action(value);Console.Writeline("Value :"+value+" Result:"+res);}

  

Action委託和Func委託
  • 除了我們自己定義的委託之外,系統還給我們提供過來一個內建的委託類型
  • ActionFunc
  • Action委託引用了一個void傳回型別的方法,T表示方法參數
  • 先看Action委託有哪些
    • Action
    • Action<in T>
    • Action<in T1,in T2>
    • Action<in T1,in T2 .... inT16>
  • Func引用了一個帶有一個傳回值的方法,它可以傳遞0或者多到16個參數類型,和一個傳回型別
    • Func<out TResult>
    • Func<in T,out TResult>
    • Func<int T1,inT2,,,,,,in T16,out TResult>
案例1
  • delegate double DoubleOp(double x); 如何用Func表示

  • Func<double,double>

案例2-對int類型排序
  • 對集合進行排序,冒泡排序
bool swapped = true;do{swapped = false;for(int i =0;i<sortArray.Length -1;i++){if(sortArray[i]>sortArray[i+1]){int temp= sortArray[i];sortArray[i]=sortArray[i+1];sortArray[i+1]=temp;swapped = true;}}}while(swapped);

  

  • 這裡的冒泡排序只適用於int類型的,如果我們想對他進行擴充,這樣它就可以給任何對象排序。
案例2-僱員類
class Employee{public Employ(string name,decimal salary){this.Name = name;this.Salary = salary;}public string Name{get;private set;}public decimal Salary{get;private set;}public static bool CompareSalary(Employee e1,Employee e2){return e1.salary>e2.salary;}}

  

案例2-通用的排序方法
public static void Sort<T>( List<T> sortArray,Func<T,T,bool> comparision ){bool swapped = true;do{swapped = false;for(int i=0;i<sortArray.Count-1;i++){if(comparision(sortArray[i+1],sortArray[i])){T temp = sortArray[i];sortArray[i]=sortArray[i+1];sortArray[i+1]=temp;swapped = true;}}}while(swapped);}

  

案例2-對僱員類排序
static void Main(){Employee[] employees = {new Employee("Bunny",20000),new Employee("Bunny",10000),new Employee("Bunny",25000),new Employee("Bunny",100000),new Employee("Bunny",23000),new Employee("Bunny",50000),};Sort(employees,Employee.CompareSalary);// 輸出}

  

多播委託
  • 前面使用的委託都只包含一個方法的調用,但是委託也可以包含多個方法,這種委託叫做多播委託。使用多播委託就可以按照順序調用多個方法,多播委託只能得到調用的最後一個方法的結果,一般我們把多播委託的傳回型別聲明為void

    • Action action1 = Test1;
    • action2+=Test2;
    • action2-=Test1;
  • 多播委託包含一個逐個調用的委託集合,如果通過委託調用的其中一個方法拋出異常,整個迭代就會停止。

  • 取得多播委託中所有方法的委託:

Action a1 = Method1;a1+=Method2;Delegate[] delegates=a1.GetInvocationList();foreach(delegate d in delegates){//d();d.DynamicInvoke(null);}// 遍曆多播委託中所有的委託,然後單獨調用

  

匿名方法
  • 到目前為止,使用委託,都是先定義一個方法,然後把方法給委託的執行個體。但還有另外一種使用委託的方式,不用去定義一個方法,應該說是使用匿名方法(方法沒有名字)。
Func<int,int,int> plus = delegate (int a,int b){int temp = a+b;return temp;};int res = plus(34,34);Console.WriteLine(res);

  

  • 在這裡相當於直接把要引用的方法直接寫在了後面,優點是減少了要編寫的代碼,減少代碼的複雜性
Lambda運算式-表示一個方法的定義
  • 從C#3.0開始,可以使用Lambda運算式代替匿名方法。只要有委託參數類型的地方就可以使用Lambda運算式。剛剛的例子可以修改為
  Func<int,int,int> plus = (a,b)=>{ int temp= a+b;return temp; };  int res = plus(34,34);  Console.WriteLine(res);

  

  • Lambda運算子“=>”的左邊列出了需要的參數,如果是一個參數可以直接寫 a=>(參數名自己定義),如果多個參數就使用括弧括起來,參數之間以,間隔
多行語句
  • 如果Lambda運算式只有一條語句,在方法快內就不需要花括弧和return語句,編譯器會自動添加return語句
Func<double,double> square = x=>x*x;// 添加花括弧,return語句和分號是完全合法的Func<double,double> square = x=>{return x*x;}

  

  • 如果Lambda運算式的實現代碼中需要多條語句,就必須添加花括弧和return語句。
Lambda運算式外部的變數
  • 通過Lambda運算式可以訪問Lambda運算式塊外部的變數。這是一個非常好的功能,但如果不能正確使用,也會非常危險。樣本:
int somVal = 5;Func<int,int> f = x=>x+somVal;Console.WriteLine(f(3));//8somVal = 7;Console.WriteLine(f(3));//10

  

  • 這個方法的結果,不但受到參數的控制,還受到somVal變數的控制,結果不可控,容易出現編程問題,用的時候要謹慎。
事件
  • 事件(event)基於委託,為委託提供了一個發布/訂閱機制,我們可以說事件是一種具有特殊簽名的委託。 什麼是事件? 事件(Event)是類或對象向其他類或對象通知發生的事情的一種特殊簽名的委託. 事件的聲明 public event 委託類型 事件名; 事件使用event關鍵詞來聲明,他的返回類值是一個委託類型。 通常事件的命名,以名字+Event 作為他的名稱,在編碼中盡量使用規範命名,增加代碼可讀性。
  • 為了更加容易理解事件,我們還是以前面的動物的樣本來說明,有三隻動物,貓(名叫Tom),還有兩隻老鼠(Jerry和Jack),當貓叫的時候,觸發事件(CatShout),然後兩隻老鼠開始逃跑(MouseRun)。接下來用代碼來實現。(設計模式-觀察者模式)
Cat類和Mouse類
      class Cat      {          string catName;          string catColor { get; set; }          public Cat(string name, string color)          {              this.catName = name;              catColor = color;         }         public void CatShout()         {             Console.WriteLine(catColor+" 的貓 "+catName+" 過來了,喵!喵!喵!\n");             //貓叫時觸發事件             //貓叫時,如果CatShoutEvent中有登記事件,則執行該事件             if (CatShoutEvent != null)                 CatShoutEvent();         }         public delegate void CatShoutEventHandler();         public event CatShoutEventHandler CatShoutEvent;     }     class Mouse     {         string mouseName;         string mouseColor { get; set; }         public Mouse(string name, string color)         {             this.mouseName = name;             this.mouseColor = color;         }         public void MouseRun()         {             Console.WriteLine(mouseColor + " 的老鼠 " + mouseName + " 說:\"老貓來了,快跑!\"  \n我跑!!\n我使勁跑!!\n我加速使勁跑!!!\n");         }     }

  

運行代碼結果
  Console.WriteLine("[情境說明]: 一個月明星稀的午夜,有兩隻老鼠在偷油吃\n");              Mouse Jerry = new Mouse("Jerry", "白色");              Mouse Jack = new Mouse("Jack", "黃色");                            Console.WriteLine("[情境說明]: 一隻黑貓躡手躡腳的走了過來\n");              Cat Tom = new Cat("Tom", "黑色");              Console.WriteLine("[情境說明]: 為了安全的偷油,登記了一個貓叫的事件\n");             Tom.CatShoutEvent += new Cat.CatShoutEventHandler(Jerry.MouseRun);             Tom.CatShoutEvent += new Cat.CatShoutEventHandler(Jack.MouseRun);             Console.WriteLine("[情境說明]: 貓叫了三聲\n");             Tom.CatShout();             Console.ReadKey();

  

事件與委託的聯絡和區別
  • 事件是一種特殊的委託,或者說是受限制的委託,是委託一種特殊應用,只能施加+=,-=操作符。二者本質上是一個東西。

  • event ActionHandler Tick; // 編譯成建立一個私人的委託樣本, 和施加在其上的add, remove方法.

  • event只允許用add, remove方法來操作,這導致了它不允許在類的外部被直接觸發,只能在類的內部適合的時機觸發。委託可以在外部被觸發,但是別這麼用。

  • 使用中,委託常用來表達回調,事件表達外發的介面。

  • 委託和事件支援靜態方法和成員方法, delegate(void * pthis, f_ptr), 支援靜態返方法時, pthis傳null.支援成員方法時, pthis傳被通知的對象.

  • 委派物件裡的三個重要欄位是, pthis, f_ptr, pnext, 也就是被通知對象引用, 函數指標/地址, 委託鏈表的下一個委託節點.

 

C# 委託

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.