Delegate比較全面的例子(需整理)

將Delegate理解爲接口,只有一個方法的接口,這樣最容易理解。這個方法只有聲明,沒有實現,實現在別的類。(實際上應該把它看作函數指針,不過接口更容易理解些。)

在你的類中有一個Delegate就相當於有一個接口。通過這個接口你可以調用一個方法,而這個方法在別的類定義,由別的類來幹。

爲了說的形象一點,舉個例子:

學生考試完後成績出來了,考的好了老師要表揚,考的不好了老師要批評。

 

使用接口的方法:


using
 System; 

public class Student

{

     private IAdviser adviser;

 

     public void SetAdviser(IAdviser iadviser)

     {

         adviser = iadviser;

     }

 

     private int score;

 

     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

              if (adviser != null)

              {

                   string result = adviser.Advise(score);

                   Console.Out.WriteLine("學生收到老師返回的結果\t"+result);

              }

         }

     }

 } 

public
 interface IAdviser

{

     string Advise(int score);

}

 

public class Teacher : IAdviser

{

     public string Advise(int score)

     {

         if (score < 60)

         {

              Console.Out.WriteLine(score+"老師說加油");

              return "不及格";

         }

         else

         {

              Console.Out.WriteLine(score+"老師說不錯");

              return "及格";

         }

     }

 

 

}

 

class MainClass

{

     [STAThread]

     private static void Main(string[] args)

     {

         IAdviser teacher = new Teacher();

         Student s = new Student();

         s.SetAdviser(teacher);

 

         Console.Out.WriteLine("學生得到50分");

         s.SetScore(50);

 

         Console.Out.WriteLine("\n學生得到75分");

         s.SetScore(75);

 

         Console.ReadLine();

     }

}

 

使用Delegate的方法:

using System;

using System.Threading;

 

public class Student

{

 

     private int score;

 

     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

              if (AdviseDelegateInstance!= null)

              {

                   string result=AdviseDelegateInstance(score);

                   Console.Out.WriteLine("學生收到老師返回的結果\t"+result);

              }

         }

     }

 

     public  delegate string AdviseDelegate(int score);

        

     public AdviseDelegate AdviseDelegateInstance;

}

 

public class Teacher

{

     public string Advise(int score)

     {

         if(score<60)

         {

              Console.Out.WriteLine(score+"老師說加油");

              return "不及格";

         }

         else

         {

              Console.Out.WriteLine(score+"老師說不錯");

              return "及格";

         }

     }

}

 

class MainClass

{

     [STAThread]

     static void Main(string[] args)

     {

         Teacher teacher=new Teacher();

         Student s=new Student();

 

         s.AdviseDelegateInstance=new Student.AdviseDelegate(teacher.Advise);

        

         Console.Out.WriteLine("學生得到50分");

         s.SetScore(50);

 

         Console.Out.WriteLine("\n學生得到75分");

         s.SetScore(75);

 

         Console.ReadLine();

     }



如果老師很忙不能及時回覆怎麼辦?比如這樣: 

public class Teacher

{

     public string Advise(int score)

     {

         Thread.Sleep(3000);

         if(score<60)

         {

              Console.Out.WriteLine(score+"老師說加油");

              return "不及格";

         }

         else

         {

              Console.Out.WriteLine(score+"老師說不錯");

              return "及格";

         }

     }


總不能讓學生一直等下去吧,採用多線程併發的辦法。 
Interface的解決辦法:  
     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

              if (adviser != null)

              {

                   Thread.adviserThread=new Thread(new ThreadStart(adviser.Advise()));

                   adviserThread.Start();

              }

         }

     }


但是它不能使用帶參數的函數,怎麼辦?(誰知道方法請指教) 
.Net2.0提供了新的方法ParameterizedThreadStart 


Delegate解決(異步調用):

     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

              if (AdviseDelegateInstance!= null)

              {

                     AdviseDelegateInstance.BeginInvoke(score,null,null);                    

              }

         }

     }

不過這樣我們失去了老師的返回結果,不知道有沒有及格了。

採用輪訊的方法去獲得結果:

     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

              if (AdviseDelegateInstance!= null)

              {

 

                       IAsyncResult res = AdviseDelegateInstance.BeginInvoke(score,nullnull);

 

                       while( !res.IsCompleted ) System.Threading.Thread.Sleep(1);

 

                       string result = AdviseDelegateInstance.EndInvoke(res);

                       Console.Out.WriteLine("學生收到老師返回的結果\t"+result);

                  

              }

         }

     }

 

不過這樣主線程又被阻塞了,採用回調的方式: (注:接口也可以採用回調的方式獲得返回值)

     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

              if (AdviseDelegateInstance!= null)

              {

                   IAsyncResult res = AdviseDelegateInstance.BeginInvoke(score, newSystem.AsyncCallback(CallBackMethod), null);

              }

         }

     }

 

     private void CallBackMethod(IAsyncResult asyncResult)

     {  

         string result = AdviseDelegateInstance.EndInvoke(asyncResult);

 

         Console.Out.WriteLine("學生收到老師返回的結果\t" + result);

     } 


這樣就比較得到了一個比較好的解決方案了。我們再來看看BeginInvoke的第四個參數是幹嗎的呢?


     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

              if (AdviseDelegateInstance!= null)

              {

                   AdviseDelegateInstance.BeginInvoke(score, new System.AsyncCallback(CallBackMethod), "idior");

              }

         }

     }

 

     private void CallBackMethod(IAsyncResult asyncResult)

     {

         string result = AdviseDelegateInstance.EndInvoke(asyncResult);

         string stateObj=(string)asyncResult.AsyncState;

 

         Console.Out.WriteLine("學生{0}收到老師返回的結果\t" + result,stateObj.ToString());

     }

 

哦,原來它可以用來標記調用者的一些信息。(這裏採取的是硬編碼的方式,你可以把它改爲學生的id之類的信息)。 


總結:Delegate類似與Interface但是功能更加強大和靈活,它甚至還可以綁定到Static方法只要函數簽名一致,而且由於+=操作符的功能,實現多播也是極爲方便(即Observer模式),在此不再舉例。 

(補充:多播的時候改一下SetScore函數) 

     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

             

              if (AdviseDelegateInstance!= null)

              {

                   foreach( AdviseDelegate ad in AdviseDelegateInstance.GetInvocationList())

                   {

                       ad.BeginInvoke(score, new System.AsyncCallback(CallBackMethod), "idior");

                   }

              }

         }

     }

 

本文沒什麼新的內容,就是自己練一下手,寫個總結材料,希望對大家有幫助。.net2.0提供了更好的線程模型。

 

完整源代碼如下:

  

 

using System;

using System.Threading;

 

public class Student

{

     private int score;

 

 

     public void SetScore(int value)

     {

         if (value > 100 || value < 0)

         {

              Console.Out.WriteLine("分數不對");

         }

         else

         {

              score = value;

              if (AdviseDelegateInstance!= null)

              {

                   AdviseDelegateInstance.BeginInvoke(score, new System.AsyncCallback(CallBackMethod), "idior");

              }

         }

     }

 

     private void CallBackMethod(IAsyncResult asyncResult)

     {

         string result = AdviseDelegateInstance.EndInvoke(asyncResult);

         string stateObj=(string)asyncResult.AsyncState;

 

         Console.Out.WriteLine("學生{0}收到老師返回的結果\t" + result,stateObj);

     }

 

    

 

     public delegate string AdviseDelegate(int score);

 

     public AdviseDelegate AdviseDelegateInstance;

 

 

}

 

public class Teacher

{

     public string Advise(int score)

     {

         Thread.Sleep(3000);

         if (score < 60)

         {

              Console.Out.WriteLine(score + "老師說加油");

              return "不及格";

         }

         else

         {

              Console.Out.WriteLine(score + "老師說不錯");

              return "及格";

         }

     }

}

 

class MainClass

{

     [STAThread]

     private static void Main(string[] args)

     {

         Teacher teacher = new Teacher();

         Student s = new Student();

 

         s.AdviseDelegateInstance= new Student.AdviseDelegate(teacher.Advise);

 

         Console.Out.WriteLine("學生得到50分");

         s.SetScore(50);

 

         Console.Out.WriteLine("\n學生得到75分");

         s.SetScore(75);

 

 

         Console.ReadLine();

     }


參考資料: .NET Delegates: A C# Bedtime Story  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章