一、簡述:
委托對與我們編程人員來說,一點都不陌生,在實際工作過程中,或多或少都應該是接觸過
但是對與編程新手來說,對與委托的理解和使用應該還是一個坎,但是只要理解清楚了,這個坎也就過去了。
最近也經常有人在問關於委托的使用的相關問題,在此我花點時間,對與委托的個人理解進行一個總結,希望能夠給大家有所幫助作用。
二、定義:
委托,其實在我們日常生活中,也經常用到委托的,比如:律師其實就是充當了一個委托的角色,當事人委托律師在法庭上對其訴訟辯護。
在c#中,委托簡單的理解就是將一個方法以參數的形式傳遞到另外一個方法中去,有點類似於c++中的指針的概念。
三、實現委托的步驟:
在委托定義的時候,我們只需要定義一個結構體,至於具體的實現,需要在具體的委托方法中來實現。
實現委托的步驟,我總結如下:
其一、定義:要聲明一個委托的結構體:delegate void Mydelegate(type1 para1,type2 para2);
其二、聲明:聲明就是要聲明一個委托變量:Mydelegate myDel;
其三、實例化:就是要對聲明的委托對象實例化具體的委托方法:myDel=new Mydelegate(obj.InstanceMethod);
其四、參數傳遞:簡單的理解,就是將委托以一個參數的形式傳遞給一個方法:MyMethod(myDel);
其五、委托方法執行:這個和普通方法實現調用一樣,就是在方法MyMethod裡面調用執行委托的方法:myDel(obj.InstanceMethod)
四、使用
委托的使用,根據平時的開經驗,委托其實在實際的使用中,有兩種場景:
其一、同步使用:同步執行委托,阻塞主流程(和平時的方法執行效果一樣)
namespace MyCalculat
{
/// <summary>
/// 定義一個委托
/// </summary>
/// <param name="num1">闡述1</param>
/// <param name="num2">參數2</param>
/// <returns>處理結果</returns>
public delegate int MyDelegate(int num1, int num2);
/// <summary>
/// Calculat類
/// </summary>
public class Calculat
{
public int Calcul(int num1,int num2,int type ) {
MyDelegate myDelegate;
switch (type) {
case 1:
myDelegate = new MyDelegate(this.Add);
break;
case 2:
myDelegate = new MyDelegate(this.Reduce);
break;
////
//// 其他邏輯
////
default:
myDelegate = new MyDelegate(this.Add);
break;
}
return 0;
}
/// <summary>
/// 計算具體邏輯處理
/// </summary>
/// <param name="calDel">MyDelegate計算委托變量</param>
/// <param name="num1">參數1</param>
/// <param name="num2">參數2</param>
/// <returns>計算處理結果</returns>
public int CalculOpert(MyDelegate calDel, int num1, int num2)
{
////
//// 其他業務邏輯處理
////
//// 委托調用處理--同步調用
return calDel.Invoke(num1,num2);
}
/// <summary>
/// 相加
/// </summary>
/// <param name="num1">參數1</param>
/// <param name="num2">參數2</param>
/// <returns>結果</returns>
public int Add(int num1, int num2) {
return num1 + num2;
}
/// <summary>
/// 相法
/// </summary>
/// <param name="num1">參數1</param>
/// <param name="num2">參數2</param>
/// <returns>結果</returns>
public int Reduce(int num1, int num2)
{
return num1 - num2;
}
}
}
其二、異步使用:不阻塞主流程的執行,異步線程去執行委托方法裡面的邏輯
namespace MyCalculat
{
/// <summary>
/// 定義一個委托
/// </summary>
/// <param name="num1">闡述1</param>
/// <param name="num2">參數2</param>
/// <returns>處理結果</returns>
public delegate int MyDelegate(int num1, int num2);
/// <summary>
/// Calculat類
/// </summary>
public class AcyCalculat
{
public int Calcul(int num1,int num2,int type ) {
MyDelegate myDelegate;
switch (type) {
case 1:
myDelegate = new MyDelegate(this.Add);
break;
case 2:
myDelegate = new MyDelegate(this.Reduce);
break;
////
//// 其他邏輯
////
default:
myDelegate = new MyDelegate(this.Add);
break;
}
return 0;
}
/// <summary>
/// 計算具體邏輯處理
/// </summary>
/// <param name="calDel">MyDelegate計算委托變量</param>
/// <param name="num1">參數1</param>
/// <param name="num2">參數2</param>
/// <returns>計算處理結果</returns>
public int CalculOpert(MyDelegate calDel, int num1, int num2)
{
int resout = 0;
////
//// 其他業務邏輯處理
////
//// 委托調用處理--異步調用
//// 異步執行完畢後,無需回調方法
calDel.BeginInvoke(num1, num2, null, null);
//// 異步執行完畢後,有回調方法
calDel.BeginInvoke(num1, num2, new AsyncCallback(this.AsyncOpert), new int[] { num1, num2 });
return resout;
}
/// <summary>
/// 處理異步執行結果邏輯
/// </summary>
/// <param name="resout">異步處理結果</param>
public void AsyncOpert(IAsyncResult resout) {
MyDelegate myDel = (MyDelegate)((AsyncResult)resout).AsyncDelegate;
//// 獲取異步處理結果
int res = myDel.EndInvoke(resout);
//// 委托方法參數
int[] lisNum = (int[])resout.AsyncState;
if (res>0)
{
/////
///// 業務邏輯處理
/////
}
else
{
/////
///// 業務邏輯處理
/////
}
}
/// <summary>
/// 相加
/// </summary>
/// <param name="num1">參數1</param>
/// <param name="num2">參數2</param>
/// <returns>結果</returns>
public int Add(int num1, int num2) {
//// 其它業務邏輯處理
return num1 + num2;
}
/// <summary>
/// 相法
/// </summary>
/// <param name="num1">參數1</param>
/// <param name="num2">參數2</param>
/// <returns>結果</returns>
public int Reduce(int num1, int num2)
{
//// 其它業務邏輯處理
return num1 - num2;
}
}
}
委托結合反射的使用:這中情況的使用場景是:當不同的委托其對於的參數個數或者參數類型不盡相同,那麼這時候就在調用委托方法時,就不能簡簡單單的調用執行
這種情況在實際工作中場景舉例:比如我們在使用緩存機制時候,都要使用到委托通反射相結合使用。
/// <summary>
/// Calculat類
/// </summary>
public class Calculat
{
/// <summary>
/// 獲取產品詳情
/// </summary>
/// <param name="proKeyID">產品ID</param>
/// <returns>獲取結果</returns>
public string GetProInfor(string proKeyID)
{
string proInfor = string.Empty;
proInfor = ChachHelp.GetBusData<string>(new Func<string, string>(new ProBuss().GetProInfor), "proDetile" + proKeyID, 60000, proKeyID);
return proInfor;
}
/// <summary>
/// 獲取用戶常用產品
/// </summary>
/// <param name="userID">用戶ID</param>
/// <param name="cout">獲取條數</param>
/// <returns>獲取結果</returns>
public string GetCommonProInto(string userID, int cout)
{
string commonProInto = string.Empty;
commonProInto = ChachHelp.GetBusData<string>(new Func<string, int, string>(new ProBuss().GetCommonProInto), "commonProInto" + userID, 60000, userID, cout);
return commonProInto;
}
}
/// <summary>
/// 產品相關操作的業務邏輯處理
/// </summary>
public class ProBuss
{
/// <summary>
/// 獲取產品詳情
/// </summary>
/// <param name="proKeyID">產品ID</param>
/// <returns>獲取結果</returns>
public string GetProInfor(string proKeyID)
{
string proInfor = string.Empty;
////---
//// 具體產品詳情的邏輯處理
///---
return proInfor;
}
/// <summary>
/// 獲取用戶常用產品
/// </summary>
/// <param name="userID">用戶ID</param>
/// <param name="cout">獲取條數</param>
/// <returns>獲取結果</returns>
public string GetCommonProInto(string userID, int cout)
{
string commonProInto = string.Empty;
////---
//// 獲取用戶常用產品的邏輯處理
///---
return commonProInto;
}
}
/// <summary>
/// 緩存操作類
/// </summary>
public class ChachHelp
{
/// <summary>
/// 獲取緩存方法
/// </summary>
/// <typeparam name="T">返回數據類型</typeparam>
/// <param name="dele">數據獲取方法</param>
/// <param name="cacheKey">緩存建</param>
/// <param name="cacheDuration">緩存時間</param>
/// <param name="objs">具體的參數集合</param>
/// <returns>獲取結果</returns>
public static T GetBusData<T>(Delegate dele, string cacheKey, int cacheDuration, params object[] objs)
{
object obj = null;
try
{
///// obj =//// 具體調用緩存獲取數據方法;
}
catch (Exception ex)
{
//// 吃掉異常
}
//// 如果緩存中沒有獲取到數據,那麼就直接通過方法獲取數據
if (obj == null)
{
string assemblyName = dele.Target.GetType().Assembly.FullName;
string typeName = dele.Target.GetType().FullName;
object instance = Assembly.Load(assemblyName).CreateInstance(typeName);
MethodInfo methodInfo = dele.Method;
obj = methodInfo.Invoke(instance, objs);
if (obj != null)
{
//// 在獲取到數據後,應當將獲取到數據,存儲記得到緩存中去
//// 緩存存儲具體方法邏輯
}
}
//// 類型轉換,將obj轉換為對應的數據類型
//// 此處先簡略的直接用強制轉換一波
T tobj = (T)obj;
return tobj;
}
}
五、小結:
從上面的委托代碼中可以發現,引入委托後,編程人員可以把方法的引用封裝在委托對象中
(把過程的調用轉化為對象的調用,充分體現了委托加強了面向對象編程的思想。),
然後把委托對象傳遞給需要引用方法的代碼,這樣在編譯的過程中我們並不知道調用了哪個方法,
這樣一來,C#引入委托機制後,使得方法聲明和方法實現的分離,充分體現了面向對象的編程思想。