有些时间 不用 c#了 ,想 写 委托 和 事件 又会 卡下 ,之前也没认真总结过。干脆 做个小结 。
什么是委托:狭义,不安全函数的指针。不安全在哪里: 任何地方都可以调用委托对象。(实际上委托对象才是函数的指针,而delegate只是一个语法)
什么是事件:狭义,安全的函数指针,安全在哪里:只允许包含事件的类,的内部调用。
联系和区别:
delegate关键字类比于class关键字, 定义的是一种委托类型,需要再创建委托对象.
用event关键字来修饰创建委托对象行为,那么就成了一个特殊的委托对象,就是事件 。
所以delegate是类,event是修饰语,好比private.
光板 delegate对象,可以到处调用它。event 修饰的delegate对象,只能在 “event 修饰的delegate对象” 所属类中使用。
还有一点语法糖,event只允许+=,而不支持=.因为=,可能会在你需要添加的时候,写成=,会覆盖掉之间的方法。
写完,终于感觉好点了。
委托 :
1.概念:个人 理解 ,加强版的 函数指针,可以存放多个函数 指针 ,算是函数指针集合。但是提供了异步的高级特性(另开一个线程去调用这个函数指针)
2。 用途:需要对某个方法进行多态或延迟执行的情况下。表现在某个固定模块,先写好函数意图,实现由模块外定义和修改。而固定模块不修改代码。
但会导致同样满足要求的工厂模式乱入,区分,工厂模式是在对象级别的延迟和多态。而委托是方法级别的延迟和多态。
3.常用用法举例:处理消息模块(固定模块),模块编写处理流程。具体哪个方法处理或哪几个方法处理 ,由外部定义实现 。
4.缺点:委托无限制,可以直接在任何地方,使用委托对象,进行调用。而事件,限制在包含事件的类内部。
4.简介使用:一个类A里面定义delegate,并定义delegate对象,那么类A的方法FUNB就可以把delegate对象当作函数一样调用。
主函数 给 类A的对象中的delegate对象,附加上和delegate原型相同的函数名FUNC。那么主函数,就可以调用A的方法FUNB。 而最终是调用附加上的FUNC方法。
class KernelModule//固定模块,内部成员必须要有委托(函数指针),来表达意图,而实现来自于外部。 { public delegate string PMSGHandle(string msg);//需要一个函数指针 public PMSGHandle impHandle;//函数指针对象 public void ProcessMsg(string msg) {
//一些流程
if (impHandle != null)
{
//impHandle(msg);//调用函数指针来调用模块外方法。 impHandle.BeginInvoke(msg, callbacka, "info");//特性,提供异步调用,并提供回调函数。我去。c#真是逆了天了。使用起来真方便。
}
} public void callbacka(System.IAsyncResult iar) { //获取绑定函数的引用 AsyncResult ar = (AsyncResult)iar; PMSGHandle delBp = (PMSGHandle)ar.AsyncDelegate; //等待函数执行完毕 string result = delBp.EndInvoke(iar); Console.Write("callback ret:"+ result); } } class Program { static string pmsg(string msg)//意图的实现1 { Console.Write("process fun1:" + msg + Environment.NewLine); return "pmsg do it"; } static string pmsg2(string msg)//意图的实现2 { Console.Write("process fun2:" + msg + Environment.NewLine); return "pmsg2 do it"; } static void Main(string[] args) { string recvMsg = "0101"; KernelModule myKernel = new KernelModule();//创建模块对象。 myKernel.impHandle = pmsg2;//给模块的委托赋值(把函数指针传递)。 //myKernel.impHandle += pmsg;//委托的特性,可以多路委托。(异步调用只能由一个委托对象) myKernel.ProcessMsg(recvMsg);//调用模块对象的方法。
// myKernel.impHandle(recvMsg);//编译 通过,对于大多数面向对象设计框架下情况下。非常危险。因为委托一般是在类内部,调用的。
Thread.Sleep(2000); } }
2.事件
概念:对委托的实例化提供了一些限制的一种语法 。public event PMSGHandle impHandle public PMSGHandle impHandle 。2个语句。都是生产委托对象。但是加了event后。这个对象进行了一些安全操作限制。
用途:跟委托一样。
小结:外部调用事件,会有编译错误。KernelModule.impHandle”只能出现在 += 或 -= 的左边(从类型“KernelModule”中使用时除外)
举例:
class KernelModule//固定模块,内部成员必须要有委托(函数指针),来表达意图,而实现来自于外部。 { public delegate string PMSGHandle(string msg);//需要一个函数指针 public event PMSGHandle impHandle;//多写一个event关键字。生成一个event对象,而不是一个delegate对象。 //public PMSGHandle impHandle;//函数指针对象 public void ProcessMsg(string msg) {
if (impHandle != null)
{ impHandle(msg);//调用函数指针来调用模块外方法。 //impHandle.BeginInvoke(msg, callbacka, "info");//特性,提供异步调用,并提供回调函数。我去。c#真是逆了天了。使用起来真方便。
}
} public void callbacka(System.IAsyncResult iar) { //获取绑定函数的引用 AsyncResult ar = (AsyncResult)iar; PMSGHandle delBp = (PMSGHandle)ar.AsyncDelegate; //等待函数执行完毕 string result = delBp.EndInvoke(iar); Console.Write("callback ret:"+ result); } } class Program { static string pmsg(string msg)//意图的实现1 { Console.Write("process fun1:" + msg + Environment.NewLine); return "pmsg do it"; } static string pmsg2(string msg)//意图的实现2 { Console.Write("process fun2:" + msg + Environment.NewLine); return "pmsg2 do it"; } static void Main(string[] args) { string recvMsg = "0101"; KernelModule myKernel = new KernelModule();//创建模块对象。 myKernel.impHandle += pmsg2;//给模块的事件handle添加event,不能再使用=号了(把函数指针传递)。 myKernel.impHandle += pmsg;//委托的特性,可以多路委托。(异步调用只能由一个委托对象) myKernel.ProcessMsg(recvMsg);//调用模块对象的方法。
myKernel.impHandle(recvMsg);//编译错误 KernelModule.impHandle”只能出现在 += 或 -= 的左边(从类型“KernelModule”中使用时除外) Thread.Sleep(2000); } }