一、委託Delegate
一般的方法(Method)中,我們的參數總是string,int,DateTime...這些基本的數據類型(或者沒有參數),比如
public void HelloWorld()
{
Console.WriteLine("Hello World!");
}
public void HelloWorld(string name)
{
Console.WriteLine("Hello ,{0}!", name);
}
但是有些時候,我們希望把一個方法本身當做參數傳遞給另一個方法,比如
myObject.callMethod(HelloWorld);
在沒有委託之前,這是一件極困難的事情,委託出現以後,這就是一件很容易的事情了,簡單點講:委託就是一種能把方法當做參數來使用的類型--當然這個定義跟官方的解釋比起來極不嚴密,但易於理解
要點:
1.委託是一種類型(跟string,int,double...一樣是.net的一種基本類型)
2.委託的定義必須與最終被調用的方法保持簽名一致
比如:下面代碼中的
delegate void D1(); 與 static void HelloWorld1(),我們拋開前面的類型關鍵字delegate與static,他們的簽名都是void X()
void D2(string myName);與void HelloWorld2(string name); void HelloWorld3(string name);它們的簽名格式都是 void X(string Y)
3.委託的好處之一在於可以保持簽名格式不變的情況下,動態調用不同的處理邏輯(即不同的方法)
想想系統控件中的Button類,系統並不知道按鈕按下去時到底會執行怎麼樣的邏輯(點擊後的處理,每個項目可能都不一樣,完全由需求決定),但是我們知道每個Button都有一個Click(object sender, EventArgs e)這樣的東東,沒錯,就是委託(當然封裝成了另一種衍生類型event),就是這種設計保證了統一的格式,不管你實際開發中想如何處理點擊後的邏輯,只要按這個統一的簽名來就行了
完整代碼演示:
using System;
namespace ActionStudy
{
class Program
{
delegate void D1();
delegate void D2(string myName);
static void Main(string[] args)
{
D1 d1 = new D1(HelloWorld1);
d1();
D2 d2 = new D2(HelloWorld2);
d2("Jimmy");
d2 = new D2(HelloWorld3);
d2("楊俊明");
Console.Read();
}
static void HelloWorld1()
{
Console.WriteLine("Hello World!");
}
static void HelloWorld2(string name)
{
Console.WriteLine("Hello,{0}!", name);
}
static void HelloWorld3(string name)
{
Console.WriteLine("你好,{0}!", name);
}
}
}
二、匿名方法(.net2.0開始支持)
在“一、委託Delegate”的演示代碼中,我們看到委託調用方法前,至少得先定義一個簽名相同的方法,然後才能由委託調用(哪怕是隻有一行代碼的方法),好象有點煩哦,想偷懶,ok,沒問題
using System;
namespace ActionStudy
{
class Program
{
delegate void D1();
delegate void D2(string myName);
static void Main(string[] args)
{
D1 d1 = delegate
{
Console.WriteLine("Hello World!");
};
d1();
D2 d2 = delegate(string name)
{
Console.WriteLine("Hello,{0}!", name);
};
d2("Jimmy");
d2 = delegate(string name)
{
Console.WriteLine("你好,{0}!", name);
};
d2("楊俊明");
Console.Read();
}
}
}
運行效果完全相同,只是省去了方法的單獨定義部分
到了.net 3.0這種偷懶的作風更誇張,看下面的代碼(利用了Lambda表達式)
using System;
namespace ActionStudy
{
class Program
{
delegate void D1();
delegate void D2(string myName);
static void Main(string[] args)
{
D1 d1 = () => { Console.WriteLine("Hello World!"); };
d1();
D2 d2 = (string name) => { Console.WriteLine("Hello,{0}!", name); };
d2("Jimmy");
d2 = (string name) => { Console.WriteLine("你好,{0}!", name); };
d2("楊俊明");
Console.Read();
}
}
}
運行效果仍然沒變,初次接觸者可能感覺很怪,其實我也覺得怪,不過很多大牛們都喜歡這樣用,所以至少還是要能看得懂,否則別人會說"你 Out了" :)
三、Action
Action的本質就是委託,看它的定義:
namespace System
{
// 摘要:
// Encapsulates a method that takes no parameters and does not return a value.
public delegate void Action();
}
namespace System
{
// 摘要:
// Encapsulates a method that takes a single parameter and does not return a
// value.
//
// 參數:
// obj:
// The parameter of the method that this delegate encapsulates.
//
// 類型參數:
// T:
// The type of the parameter of the method that this delegate encapsulates.
public delegate void Action<T>(T obj);
}
當然,還有Action<T1,T2>乃至Action<T1,T2,T3,T4>參數個數從2到4的類型,不過定義都差不多
簡單點講,Action是參數從0到4,返回類型爲void(即沒有返回值)的委託
using System;
namespace ActionStudy
{
class Program
{
static Action A1;
static Action<string> A2;
static void Main(string[] args)
{
A1 = new Action(HelloWorld1);
A1();
A2 = new Action<string>(HelloWorld2);
A2("Jimmy");
A2 = (string name) => { Console.WriteLine("你好,{0}!", name); };
A2("楊俊明");
A2 = delegate(string name) { Console.WriteLine("我就是委託,{0} 你說對嗎?", name); };
A2("菩提樹下的楊過");
Console.Read();
}
static void HelloWorld1()
{
Console.WriteLine("Hello World!");
}
static void HelloWorld2(string name)
{
Console.WriteLine("Hello,{0}!", name);
}
}
}
四、Func
Func其實也是一個"託"兒,呵呵,不過這個委託是有返回值的。看下定義就知道了:
{
// 摘要:
// Encapsulates a method that has no parameters and returns a value of the type
// specified by the TResult parameter.
//
// 類型參數:
// TResult:
// The type of the return value of the method that this delegate encapsulates.
//
// 返回結果:
// The return value of the method that this delegate encapsulates.
public delegate TResult Func<TResult>();
}
namespace System
{
// 摘要:
// Encapsulates a method that has one parameter and returns a value of the type
// specified by the TResult parameter.
//
// 參數:
// arg:
// The parameter of the method that this delegate encapsulates.
//
// 類型參數:
// T:
// The type of the parameter of the method that this delegate encapsulates.
//
// TResult:
// The type of the return value of the method that this delegate encapsulates.
//
// 返回結果:
// The return value of the method that this delegate encapsulates.
public delegate TResult Func<T, TResult>(T arg);
}
同Action類似,Func的參數從1到5個,有5個不同的重載版本
代碼:
namespace ActionStudy
{
class Program
{
static Func<string> F;
static Func<DateTime, string> F2;
static void Main(string[] args)
{
F = new Func<string>(HelloWorld1);
Console.WriteLine(F());
F2 = new Func<DateTime, string>(HelloWorld2);
Console.WriteLine(F2(DateTime.Now));
Console.Read();
}
static string HelloWorld1()
{
return "Hello World!";
}
static string HelloWorld2(DateTime time)
{
return string.Format("Hello World,the time is {0}.", time);
}
}
}
五、匿名委託
ok,如果你沒有暈的話,再來看一下匿名委託,其實這也是一種偷懶的小伎倆而已
看代碼說話:
//F = new Func<string>(HelloWorld1);
其實也可以簡寫成這樣:
F = HelloWorld1;
//F2 = new Func<DateTime, string>(HelloWorld2);
其實也可以簡寫成這樣
F2 = HelloWorld2;
方法直接賦值給委託,這二個類型不同吧???
沒錯,你會發現編譯一樣能通過,系統在編譯時在背後自動幫我們加上了類似 “= new Func<...>”的東東,所以我們能偷懶一下下,這個就是匿名委託。
如果你細心的話,會發現我們在定義Button的Click處理事件時,通常是這樣的:
this.button1.Click += new EventHandler(button1_Click);
但有時候我們也可以寫成這樣:
this.button1.Click += button1_Click;
這其實就是匿名委託的應用.
六、事件event
其實,這...還是個托兒!
我們來看下按鈕Click事件的定義
// Occurs when the control is clicked.
public event EventHandler Click;
繼續刨根問底,查看EventHandler的定義:
namespace System
{
// 摘要:
// Represents the method that will handle an event that has no event data.
//
// 參數:
// sender:
// The source of the event.
//
// e:
// An System.EventArgs that contains no event data.
[Serializable]
[ComVisible(true)]
public delegate void EventHandler(object sender, EventArgs e);
}
看到了吧,就是委託!