先看看委托的概述:
•委托類似於 C++ 函數指針,但它們是類型安全的。
• 委托允許將方法作為參數進行傳遞。
• 委托可用於定義回調方法。
• 委托可以鏈接在一起;例如,可以對一個事件調用多個方法。
•方法不必與委托簽名完全匹配。 有關更多信息,請參見 在委托中使用變體(C# 和 Visual Basic)。
• C# 2.0 版引入了匿名方法的 概念,此類方法允許將代碼塊作為參數傳遞,以代替單獨定義的方法。 C# 3.0 引入了 Lambda 表達式,利用它們可以更簡練地編寫內聯代碼塊。 匿名方法和 Lambda 表達式(在某些上下文中)都可編譯為委托類型。 這些功能統稱為匿名函數。 有關 lambda 表達式的更多信息,請參見 匿名函數(C# 編程指南)。
委托是一種定義方法簽名的類型。 當實例化委托時,您可以將其實例與任何具有兼容簽名的方法相關聯。 您可以通過委托實例調用方法。
委托用於將方法作為參數傳遞給其他方法。 事件處理程序就是通過委托調用的方法。 您可以創建一個自定義方法,當發生特定事件時某個類(例如 Windows 控件)就可以調用您的方法。
例子1:
class Program { static void Main(string[] args) { Hello(); } static void Hello() { System.Console.WriteLine("Hello, Delegate!"); } }
這是一個常見的方法, 輸出一段字符串Hello, Delegate!
下面我們來把他寫成委托,
class Program { delegate void PrintHello(); static void Main(string[] args) { PrintHello ph = new PrintHello(Hello); ph.Invoke(); } static void Hello() { System.Console.WriteLine("Hello, Delegate!"); } }
這里的PrintHello的方法類型需要和Hello保持一直,另外參數也需要保持一致,現在是無參數的.講Hello作為參數傳到委托中,然后用Invoke調用.
以上代碼也會輸出,Hello, Delegate!因為invoke了這個方法.
從.net 2.0開始就使用匿名委托, 可以這樣申明
delegate { };
或者帶參數的
delegate (string i){ };
{}括號中可以寫需要執行的邏輯代碼.
有了匿名委托我們就可以偷一下懶了,可以把上面的例子改成如下:
class Program { delegate void PrintHello(); static void Main(string[] args) { PrintHello ph = delegate { System.Console.WriteLine("Hello, Delegate!"); }; ph.Invoke(); } //static void Hello() //{ // System.Console.WriteLine("Hello, Delegate!"); //} }
在.net 3.0中新加了Action<T> 無返回的委托, Predicate<T>有返回值,且返回true或false的委托.
我們可以將上面的例子改成有參數的,
class Program { static Action<string> print = delegate(string i) { System.Console.WriteLine("Hello, {0}!",i); }; static void Main(string[] args) { print.Invoke("Delegate"); } }
或者用lambda表達式替代匿名委托,進一步偷懶..
class Program { static Action<string> print = (i)=>{ System.Console.WriteLine("Hello, {0}!",i); }; static void Main(string[] args) { print.Invoke("Delegate"); } }
以上會輸出Hello,Delegate!因為將Delegate傳入到最后輸出.
再來講解一下Predicate這個只返回true or false的委托,如下:
class Program { static Predicate<string> print = (i) => { return string.IsNullOrEmpty(i); }; static void Main(string[] args) { System.Console.WriteLine(print.Invoke("Hello, Delegate!")); } }
以上代碼會輸入true因為i不是為null or empty.
在.net 3.5中又新加了Action(無返回值的委托,類似於delegate void)和Func<T,T> 帶返回參數的,參數類型是T,返回類型也可以是int,string等..
所以剛才的無參數的例子又可以寫成這樣:
class Program { static Action print = () => { System.Console.WriteLine("Hello, Delegate!"); }; static void Main(string[] args) { print.Invoke(); } }
再來看看Func<T,TReslut> 第一個T代表參數的類型,第一個TReslut代表返回結果的類型。
如下,參數的類型是int,返回的類型是string.
class Program { static Func<int,string> print = (i) => { return "Hello, Delegate!"+i.ToString(); }; static void Main(string[] args) { System.Console.WriteLine(print.Invoke(0)); } }
輸出的結果是:Hello, Delegate!0
再來看看委托的回調函數,如下:
class Program { delegate string callback(string firstName, string lastName); static void Main(string[] argss) { DoCallback("Charlie", "Wang", en_US); DoCallback("Tom", "Chen", ch_ZN); } static void DoCallback(string firstName, string lastName, callback call) { string result=call(firstName, lastName); Console.WriteLine(result); } static string en_US(string firstName, string lastName) { return firstName + " ," + lastName; } static string ch_ZN(string firstName, string lastName) { return lastName+", "+firstName; } }
輸出的結果為:
Charlie ,Wang
Chen, Tom
我們還可以將以上代碼進一步精簡,用Func代替.
class Program { static void Main(string[] argss) { DoCallback("Charlie", "Wang", en_US); DoCallback("Tom", "Chen", ch_ZN); } static void DoCallback(string firstName, string lastName, Func<string,string,string> callback) { string result = callback(firstName, lastName); Console.WriteLine(result); } static string en_US(string firstName, string lastName) { return firstName + " ," + lastName; } static string ch_ZN(string firstName, string lastName) { return lastName+", "+firstName; } }
我們還可以這樣寫.
class Program { static void Main(string[] argss) { DoCallback("Charlie", "Wang", en_US); DoCallback("Tom", "Chen", ch_ZN); DoCallback("Kevin", "Liu", (lastName, firstName) => { return string.Format("This is {0} {1}", lastName, firstName);}); } static void DoCallback(string firstName, string lastName, Func<string,string,string> callback) { string result = callback(firstName, lastName); Console.WriteLine(result); } static string en_US(string firstName, string lastName) { return firstName + " ," + lastName; } static string ch_ZN(string firstName, string lastName) { return lastName+", "+firstName; } }
輸出結果為:
Charlie ,Wang
Chen, Tom
This is Kevin Liu
委托在很多時候使用可以精簡我們的代碼,看起來比較直觀,下面是個很經典的案例:
class Program { static void Main(string[] args) { B b = new B(); } } class A { public A() { Print(); } public virtual void Print() { } } class B : A { int x = 1; int y; public B() { y = -1; } public override void Print() { System.Console.WriteLine("x={0},y={1}", x, y); } }
各位讀者看看以上代碼輸出什么?
class Program { static void Main(string[] args) { B b = new B(); b.print(); } } class A { public A() { Print(); } public virtual void Print() { } } class B : A { int x = 1; int y; public Action print = delegate { }; public B() { y = -1; this.print = Print; } public override void Print() { System.Console.WriteLine("x={0},y={1}", x, y); } }
然后再看看以上代碼又輸出什么?