將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,null, null);
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