什麼是委託?爲什麼要用委託?委託有那幾種形式?怎麼使用委託?
委託的定義:
委託是一種特殊類型的對象(也就是說,可以看作是一個特殊的類),包含一個或者多個方法的地址。
爲什麼要用委託:
當需要把一個方法進行傳遞時就需要用到委託來實現,在C/C++的時候是提取函數地址的指針進行傳遞的,但是這樣是沒有安全性的,因爲你無法對其進行安全性校驗,這就造成了編碼的不可控性,非法的數據就可能被調用。在.NET Framework中就加入了委託的概念,如果要傳遞方法,就必須把方法的細節封裝在一個新型的對象中–委託。所以委託是針對方法進行的操作,委託對數據是什麼並不關心(也是面向對象編程思路,只關心自己要處理的)。
委託有幾種形式:
1,自定義委託
2,泛型委託:Action,Func,自定義泛型委託
3,匿名委託
4,多播委託
5,Lambda形式的委託
從返回形式來看,委託可以分爲兩種。一種是有返回值的委託,一種是沒有返回值的委託(可以成爲事件委託)。這兩種形式的委託定義,聲明和委託綁定還是有區別的。如下做簡要展示。
//定義有返回值的委託
pubilc delegate string GenericDelegate<T,S>(T title, S author);
//定義無返回值的事件委託
public delegate void GenericDelegateEvent<E,P>(E Name, P Address);
public class GenericDelegateClass<V,F>
{
//聲明委託
GenericDelegate<V,F> GDeleValue;
//聲明事件委託
GenericDelegateEvent<V,F> GDeleEvent = null;
}
//綁定委託
pubilc void Click(object sender , EventArgs e)
{
GenericDelegateClass<string ,string> gdc = new GenericDelegateClass<string ,string>();
//綁定委託,可以用=。
gdc.GDeleValue = new GenericDelegate<string,string>(Delegate);
//綁定事件委託,事件委託只能用+=,-=。
gdc.GDeleEvent += new GenericDelegateEvent<stirng,string>(EventDelegate);
public string Delegate<T,S>(T title,S author)
{
return title.ToString() + author;
}
private void EventDelegate<V, F>(V name, F address)
{
//
}
}
下面舉個例子來幫助理解委託的工作方式,這也是面向對象編程的思維方式。
故事裏面有三個要素:任務下達,你的組長,你。
今天公司給你們組下達了一個開發任務,你組長接受到任務之後覺得你適合完成這個任務,就將任務委託給了你去實現,你做完之後把結果給你組長。
其實委託的實現流程和上面是一樣的(所以叫委託= =)
怎麼使用委託
下面用事件來闡述如何使用委託
委託的定義語法如下:
delegate void IntMethodInvoker(int x);
關鍵詞delegate 表示這是個委託對象,void和int參數表示該委託包含的方法帶有一個int型的參數且返回值是void。這也體現了委託的安全性。(爲什麼委託的返回類型要和調用的方法的返回類型一樣,一方面是爲了保證委託的安全性,另一方面方法的處理結果要靠委託表達出來,所以要一樣)
委託的實例化
委託的實例化和普通類的實例化是一樣
IntMethodInvoker invoker = new IntMethodInvoker( );
代碼下載地址:http://download.csdn.net/download/geshicuowu/9933392
下面舉個最簡單的例子來展現委託
很明顯結果會返回:40
但是上面的這個例子顯然沒有說到點上,委託的使用看起來和直接使用x.ToString( )方法沒有什麼特別的優勢。(在後面會舉一個更能說明委託作用的一個例子。該例子主要是爲了表明委託的基本形式,以後的形式都是在此上面的擴展)
泛型委託
其實在實際的項目中,泛型委託的形式更爲常見。其中action委託表示引用一個返回void類型的方法,參數範圍是0~16個。func委託可以引用具有返回類型的方法。例如func(in T1,out TResult)
下面將舉一個泛型委託的例子,也更能體現出委託的特點。(例子來源於c#高級編程)
1:定義一個排序類,裏面聲明一個static方法,其中一個參數爲泛型委託func
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 這個類時用來演示泛型委託的
/// 冒泡排序
/// </summary>
namespace DelegateExample
{
class BubbleSort
{
/// <summary>
/// 冒泡排序方法
/// </summary>
/// <typeparam name="T">泛型參數</typeparam>
/// <param name="sortArry">傳入的排序隊列</param>
/// <param name="comparison">泛型委託</param>
/// <returns></returns>
static public bool Sort<T>(IList<T> sortArry, Func<T, T, bool> comparison)
{
for (int j = 0; j < sortArry.Count; j++)
{
for (int i = j+1; i < sortArry.Count; i++)
{
if (comparison(sortArry[j], sortArry[i]))
{
var temp = sortArry[j];
sortArry[j] = sortArry[i];
sortArry[i] = temp;
}
}
}
return false;
}
}
}
2:定義一個employee類,其中有工資的比較方法,和上面的泛型委託的參數和返回類型相匹配。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 自定義的一個員工類
/// 用來示範泛型委託的使用
/// author:zhangzhen
/// date: 2017/08/14
/// </summary>
namespace DelegateExample
{
class Employee
{
public Employee(string name, double salery)
{
Name = name;
Salery = salery;
}
public string Name
{
get;
private set;
}
public double Salery
{
get;
private set;
}
/// <summary>
/// 比較薪資的函數
/// </summary>
/// <param name="e1"></param>
/// <param name="e2"></param>
/// <returns></returns>
static public bool compare(Employee e1,Employee e2)
{
return e1.Salery < e2.Salery;
}
}
}
3:最後時實現類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/*******************************************
* 這個控制檯程序主要用來演示委託delegate的相關知識
* author:zhangzhen
* date :2017-08-10
* ******************************************/
namespace DelegateExample
{
class Program
{ //定義一個委託
delegate string GetStringInvoker();
static void Main(string[] args)
{
Employee[] employees =
{
new Employee("zhangzhen",10000000),
new Employee("xiaoming",10000),
new Employee("xiaohuang",20000),
new Employee("xiaodong",8000)
};
BubbleSort.Sort(employees, Employee.compare);
foreach(var item in employees)
{
Console.WriteLine(item.Name + " /// "+ item.Salery);
}
//讓控制檯暫停等待輸入。
Console.ReadKey();
}
}
}
輸出結果符合預期。
也就是說任何對象(只要該對象中有比較方法,且比較方法的形式符合BubbleSort類中Sort方法中的泛型委託的要求的)都可以使用Sort方法實現冒泡排序。試想,如果沒有委託(尤其是泛型委託)的話,這個效果時很難實現的。
多播委託
上面那個排序的例子中,調用一次委託就調用一次方法,如果要調用多個方法,就要多次顯示的調用這個委託,使用起來不是很方便,多播委託就比較好的解決了這個問題。
多播委託可以委託多個方法,在調用多播委託時,將按順序連續調用多個方法。(因爲不可能返回多個返回類型,因此多播委託的簽名必須是void)多播委託可以使用-=,+=來向委託列表中刪減方法或者增加方法。
使用多播委託時的注意點:
1:多播委託並不會嚴格的按照委託列表中的順序來執行,也就是說不能把有順序特定依賴的方法加到委託列表中。
2:多播委託中,如果委託鏈表中一個方法發生了異常,整個迭代就會終止。爲了避免這個問題,Delegate類中定義了GetInvocationList()方法,它返回一個Delegate對象數組,可以利用這個委託調用與委託列表中相關的方法,同時捕獲異常,並不會終止迭代。
在一些涉及業務較爲繁雜的項目中,泛型委託和多播委託一般都會結合使用。
下面就是一個比較簡單的例子(因爲多播委託中委託的方法返回類型是void,所以邏輯處理基本都是在被委託的方法中實現)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 這個類是用來演示多播委託的一個輔助類
/// </summary>
namespace DelegateExample
{
class MultiDelegate
{
static public void One()
{
Console.WriteLine("這是方法ONE");
}
static public void Two()
{
Console.WriteLine("這是方法Two");
}
}
}
下面是實現
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/*******************************************
* 這個控制檯程序主要用來演示委託delegate的相關知識
* author:zhangzhen
* date :2017-08-10
* ******************************************/
namespace DelegateExample
{
class Program
{
/*********************多播委託的演示**********************************/
Action action = MultiDelegate.One;
action += MultiDelegate.Two;
action += MultiDelegate.One;
//將Two方法從委託鏈表中移除
//action -= MultiDelegate.Two;
Delegate[] tempDelegate = action.GetInvocationList();
//下面的形式是不可行的,var沒辦法調用委託中的方法,必須用Action來修飾item
//foreach (var item in tempDelegate)
//{
// item();
//}
foreach (Action item in tempDelegate)
{
item();
}
//讓控制檯暫停等待輸入。
Console.ReadKey();
}
}
}