再看委托与事件
来源:互联网 发布:柬埔寨网络推广靠谱吗 编辑:程序博客网 时间:2024/04/28 16:27
之前接触委托也好几次了,至不过每次都只是拿来用用而已,基本只在事件、多线程更新问题处才会用到,一直对其概念都不是很清楚。
初识其只知.NET通过委托提供了了一种函数回调机制,在C/C++中非成员函数的地址只是一个内存地址,仅仅是一个地址而已,不包含其他的额外信息,因为只有方法地址,并缺少参数、特别是参数类型和返回值的类型描述,故其在C/C++中是一种不安全的类型,不过因为这些原因,非托管的函数回调效率较高。
委托就是一个代理,它负责处理跟他具有类似形态的方法,而不需要调用者亲自动手,由委托来代替执行。
1、一个简单的委托:
Publicdelegate void MyEventHandle(string value);//委托
Private voidOnAddToDelegate(string value) //交给委托执行的方法
{
MessageBox.Show(value);
}
//委托要跟呗委托的方法保持类似的形态(参数)
Public voidDo()//执行函数
{
MyEventHandle PHandle=newMyEventHandle(OnAddToDelegate);
PHandle(“Test”);
}
2、委托的两个特性
(1)协变形协变形是指方法返回的类型可以是原本返回类型的派生类:
也就是说如果你的委托定义一个返回值类型是object,那么委托所调用的方法可以返回任何一个类。(void类型没有返回值,除外:所有值类型的也不可以)
Publicdelegate object MyEventHandle(string value);
Private stringOnAddToDelegate(string value)
{
MessageBox.Show(value);
}
String 类型派生自object,故string类型可以作为委托返回值的类型。
(2)逆变性是说方法获取的参数可以是委托参数类型的基类
同样用上面的例子说明:
Publicdelegate object MyEventHandle(string value);
Privatestring OnAddToDelegate(object value) //方法获取道的参数可以是委托参数value的基类,不能是派生类
{
MessageBox.Show(value);
}
均只适用于引用类型的参数,void值类型不使用
在定义了delegate后,如果想看看编译器到底是怎么实现具体委托的,可以用IL查看一下源码,里面能看到具体的处理。
委托与事件
事件是基于委托实现的,因为在一个类中想要调用另外一个类内部的私有方法就要用到事件,而他自己本身无这样处理,故,把这部分处理交由第三方待处理,也就是委托了。
定义一个简单的事件很简单,在这里我想说的是,事件是既有委托实现的,如果没有委托的话事件这个机制也就没意义了,既然这样子,委托作为核心,那可不可以抛弃事件,自己利用委托实现一个类似事件的机制。想到这就联想到flex了,flex属于事件驱动编程语言,完全靠事件驱动,既然这样子,我就模仿一下flex。
整理思路:
所有的事件必须首先注册,注册到一个集合中,注册过的事件在特定的条件下分发下去,在这里没有顺序科研,不是先注册那个分发那个,按需分配。对于分发过的事件,必须要监听事件,只有监听过的事件才能在分发后相应。
实现:
public classEventDiapatcher
{
/// <summary>
/// 字典存储所有事件注册静态变量为了所有类都可以访问
/// </summary>
private static Dictionary<string,Delegate> m_EventList = new Dictionary<string, Delegate>();
/// <summary>
/// 注册事件监听
/// </summary>
/// <paramname="PEventName">事件名称</param>
/// <paramname="PMethod">处理事件的委托方法</param>
public void AddEventListen(stringPEventName,Delegate PMethod)
{
bool Plock = false;
Monitor.Enter(m_EventList, refPlock);
if (Plock)
{
Delegate POut = null;
if(m_EventList.TryGetValue(PEventName, out POut))
{
m_EventList[PEventName] =Delegate.Combine(POut, PMethod);
//支持委托连
}
else
{
m_EventList.Add(PEventName,PMethod);
}
}
Monitor.Exit(m_EventList);
}
/// <summary>
/// 分发事件在字典中查找注册到
/// </summary>
/// <paramname="PEventName"></param>
/// <paramname="Sender"></param>
/// <paramname="e"></param>
public void DispatchEvent(stringPEventName,object Sender,object e)
{
bool Plock = false;
Monitor.Enter(m_EventList, refPlock);
if (Plock)
{
Delegate POut = null;
if(m_EventList.TryGetValue(PEventName, out POut))
{
POut.DynamicInvoke(newobject[] { Sender, e });
}
}
Monitor.Exit(m_EventList);
}
/// <summary>
/// 删除事件
/// </summary>
/// <paramname="PEventName"></param>
/// <paramname="PMethod"></param>
public void RemoveEventLIsten(stringPEventName, Delegate PMethod)
{
bool Plock = false;
Monitor.Enter(m_EventList, refPlock);
if (Plock)
{
Delegate POut = null;
POut =Delegate.Remove(POut,PMethod);
if (POut == null)
{
m_EventList.Remove(PEventName);
}
else
{
m_EventList[PEventName] =POut;
// POut.Target
}
}
Monitor.Exit(m_EventList);
}
}
Monitor 类提供了线程安全管理,Enter给枷锁,exit解锁。可以保证多线程调用下不会冲突。具体看msdn。
测试:
此类为一个积累,凡是他的派生类都可以利用委托跳过定义事件的繁琐,很像flex。
定义2个类测试:
public class DispathObject : EventDiapatcher
{
public static readonly string AddEvent= "Add";
}
public class Test:EventDiapatcher
{
}
//事件参数
public class FeedArgs:EventArgs
{
public string Name { get; set; }
public FeedArgs(string PName)
{
Name = PName;
}
}
定义两个全局变量
DispathObject dis = newDispathObject();
Test t = new Test();
在窗体加载里为t注册事件监听:
t.AddEventListen(DispathObject.AddEvent,new EventHandler<FeedArgs>(dis_OnAddEvent));
然后再一个按钮的事件中分发事件:
dis.DispatchEvent(DispathObject.AddEvent,sender, new FeedArgs("123"));
void dis_OnAddEvent(object sender,FeedArgs e)
{ }//加入断点,进行调试
亲测可行,并支持委托连。
最后,比起定义一个事件而言,这样快速多了。平常很多人写事件都会自定义委托,我想说,委托其实都那样何必呢,需要传参数用参数对象就好了(当然不排除特殊情况)。尽量使用自带的委托,这样代码都会清晰很多。。。。。
- 再看委托与事件
- 再看事件(内含多播委托)
- 再看C#中的委托和事件
- 再看委托
- 再看委托
- 委托入门-事件与委托
- 委托与事件
- 委托与事件
- c# 委托与事件
- 委托与事件
- 事件与委托详解
- 委托与事件详解
- 委托与事件详解
- 委托与事件
- C#委托与事件
- 委托与事件
- 委托与事件
- 事件与委托趣谈
- ListView 实现点击侧边A-Z快速查找[中英文混排]
- sql2005架构
- JDBC大批量写入数据到SQLServer2000,记录数大于10000
- 网络地址转换(NAT)简介
- SQLite3的API应用(续)
- 再看委托与事件
- COLLECTION 框架
- Hi3515视频编码(H.264)笔记
- The Listener (concept)【每日一译】--20121205
- 基于HEVC的码率控制的相关提案的文献综述
- 注意Java代码的内存泄漏
- 10个出色的NoSQL数据库
- sizeof 和 sizeof(string)
- Linux多线程通信及同步