委託-非同步呼叫-泛型委託-匿名方法-Lambda表示式-事件
1. 委託
類是物件的抽象,而委託則可以看成是函式的抽象。一個委託代表了具有相同引數列表和返回值的所有函式。
class Program { delegate int CalculateDelegate(int a, int b); int add(int a, int b) { return a + b; } static void Main(string[] args) { CalculateDelegate d = new Program().add; //CalculateDelegate d = new CalculateDelegate(new Program().add); Console.WriteLine(d(1, 2)); Console.ReadKey(); } }
委託作為引數,在C#中非常常見。比如執行緒的建立,需要給一個ThreadStart或者ParameterizedThreadStart委託作為引數,而線上程執行的時候,將這個引數所指代的函式用作執行緒執行體。再比如:List<T>型別的Find方法的引數也是一個委託,它把“怎麼去查詢”或者說“怎麼樣才算找到”這個問題留給了開發人員。這有點像模板模式。
委託作為返回值一般會用在“根據不同情況決定使用不同的委託”這樣的情形下。這有點像工廠模式。
2. 非同步呼叫
非同步通過委託來完成。.net使用delegate來"自動"生成的非同步呼叫是使用了另外的執行緒(而且是執行緒池執行緒)。
class Program { static TimeSpan Boil() { DateTime begin = DateTime.Now; Console.WriteLine("水壺:開始燒水..."); Thread.Sleep(6000); Console.WriteLine("水壺:水已經燒開了!"); return DateTime.Now - begin; } delegate TimeSpan BoilingDelegate(); static void Main(string[] args) { Console.WriteLine("小文:將水壺放在爐子上"); BoilingDelegate d = new BoilingDelegate(Boil); IAsyncResult result = d.BeginInvoke(BoilingFinishedCallback, null); Console.WriteLine("小文:開始整理家務..."); for (int i = 0; i < 20; i++) { Console.WriteLine("小文:整理第{0}項家務...", i + 1); Thread.Sleep(1000); } } static void BoilingFinishedCallback(IAsyncResult result) { AsyncResult asyncResult = (AsyncResult)result; BoilingDelegate del = (BoilingDelegate)asyncResult.AsyncDelegate; Console.WriteLine("(燒水一共用去{0}時間)", del.EndInvoke(result)); Console.WriteLine("小文:將熱水灌到熱水瓶"); Console.WriteLine("小文:繼續整理家務"); } }
EndInvoke會使得呼叫執行緒阻塞,直到非同步函式處理完成。EndInvoke會使得呼叫執行緒阻塞,直到非同步函式處理完成。EndInvoke會使得呼叫執行緒阻塞,直到非同步函式處理完成。EndInvoke會使得呼叫執行緒阻塞,直到非同步函式處理完成。EndInvoke呼叫的返回值也就是非同步處理函式的返回值。
3. 泛型委託
[Serializable]
publicdelegatevoid EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs: EventArgs;
class IntEventArgs : System.EventArgs
{
public int IntValue { get; set; }
public IntEventArgs() { }
public IntEventArgs(int value)
{ this.IntValue = value; }
}
class StringEventArgs : System.EventArgs
{
public string StringValue { get; set; }
public StringEventArgs() { }
public StringEventArgs(string value)
{ this.StringValue = value; }
}
class Program
{
static void PrintInt(object sender, IntEventArgs e)
{
Console.WriteLine(e.IntValue);
}
static void PrintString(object sender, StringEventArgs e)
{
Console.WriteLine(e.StringValue);
}
static void Main(string[] args)
{
EventHandler<IntEventArgs> ihandler =
new EventHandler<IntEventArgs>(PrintInt);
EventHandler<StringEventArgs> shandler =
new EventHandler<StringEventArgs>(PrintString);
ihandler(null, new IntEventArgs(100));
shandler(null, new StringEventArgs("Hello World"));
}
}
4. 匿名方法
只需要給出方法的引數列表(甚至也可以不給)以及方法具體實現,而不需要關心方法的返回值,更不必給方法起名字。最關鍵的是,只在需要的地方定義匿名方法,保證了程式碼的簡潔。比如用於委託作為函式引數。
class Program
{
static void Main(string[] args)
{
List<string> names = new List<string>();
names.Add("Sunny Chen");
names.Add("Kitty Wang");
names.Add("Sunny Crystal");
List<string> found = names.FindAll(
delegate(string name)
{
return name.StartsWith("sunny",
StringComparison.OrdinalIgnoreCase);
});
if (found != null)
{
foreach (string str in found)
Console.WriteLine(str);
}
}
}
5. Lambda表示式
從委託的角度來看,Lambda表示式與匿名方法沒有區別。Lambda表示式的定義方式為:“([引數列表]) => 表示式”。
class Program
{
static void Main(string[] args)
{
List<string> names = new List<string>();
names.Add("Sunny Chen");
names.Add("Kitty Wang");
names.Add("Sunny Crystal");
List<string> found = names.FindAll
(
// Lambda Expression Implementation
name => name.StartsWith(
"sunny",
StringComparison.OrdinalIgnoreCase)
);
if (found != null)
{
foreach (string str in found)
Console.WriteLine(str);
}
}
}
6. 事件
事件由委託定義。事件的觸發方只需要確定好事件處理函式的簽名即可。也就是說,觸發方只需要定義在事件發生時需要傳遞的引數,而在訂閱方,只需要根據這個簽名定義一個處理函式,然後將該函式“繫結”到事件列表,就可以通過簽名中的引數,對事件做相應的處理。