一、简述:
委托对与我们编程人员来说,一点都不陌生,在实际工作过程中,或多或少都应该是接触过
但是对与编程新手来说,对与委托的理解和使用应该还是一个坎,但是只要理解清楚了,这个坎也就过去了。
最近也经常有人在问关于委托的使用的相关问题,在此我花点时间,对与委托的个人理解进行一个总结,希望能够给大家有所帮助作用。
二、定义:
委托,其实在我们日常生活中,也经常用到委托的,比如:律师其实就是充当了一个委托的角色,当事人委托律师在法庭上对其诉讼辩护。
在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 this.CalculOpert(myDelegate,num1, num2); } /// <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 void 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; } this.CalculOpert(myDelegate,num1,num2) ; } /// <summary> /// 计算具体逻辑处理 /// </summary> /// <param name="calDel">MyDelegate计算委托变量</param> /// <param name="num1">参数1</param> /// <param name="num2">参数2</param> /// <returns>计算处理结果</returns> public void CalculOpert(MyDelegate calDel, int num1, int num2) { //// //// 其他业务逻辑处理 //// //// 委托调用处理--异步调用 //// 异步执行完毕后,无需回调方法 calDel.BeginInvoke(num1, num2, null, null); //// 异步执行完毕后,有回调方法 calDel.BeginInvoke(num1, num2, new AsyncCallback(this.AsyncOpert), new int[] { num1, num2 }); } /// <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#引入委托机制后,使得方法声明和方法实现的分离,充分体现了面向对象的编程思想。