C#之委托与事件
委托与事件
废话一堆:网上关于委托、事件的文章有很多,一千个哈姆雷特就有一千个莎士比亚,以下内容均是本人个人见解。
1. 委托
1.1 委托的使用
这一小章来学习一下怎么简单的使用委托,了解一些基本的知识。
这里先看一下其他所要用到的类的信息
/// <summary>
/// 函数用例
/// </summary>
public class ManyMethodClass
{
public ManyMethodClass() { }
/// <summary>
/// 实例函数
/// </summary>
/// <param name="strmes"></param>
public void InstanceMethod(string strmes)
{
Console.WriteLine("实例函数输出:" + strmes);
}
/// <summary>
/// 静态函数
/// </summary>
/// <param name="strmes"></param>
public static void StaticMethod(string strmes)
{
Console.WriteLine("静态函数输出:" + strmes);
}
}
- 定义一个委托类型
public delegate void DisplayStringDelegate(string strmes);
- 实例化委托类型
//绑定实例函数 第一种定义方式(实例函数)
DisplayStringDelegate disstrdele_instance = new DisplayStringDelegate(new ManyMethodClass().InstanceMethod);
//绑定静态函数 第二种定义方式(静态函数)
DisplayStringDelegate disstrdele_static = new DisplayStringDelegate(ManyMethodClass.StaticMethod);
//绑定委托实例 第三种定义方式(委托实例)
DisplayStringDelegate disstrdele_delegate = new DisplayStringDelegate(disstrdele_instance);
- 调用委托实例
disstrdele_instance.Invoke("Hello Word");
disstrdele_static("Hello Word");
disstrdele_delegate("Hello Word");
(ps:这里不同的调用方式效果都是一样的,在下一节会有讲到)
最后让我们看一下最终的效果图:
1.2 委托的定义
- 委托类型是类类型
/// <summary>
/// 委托示例类
/// </summary>
public class DelegateDemonStration
{
public DelegateDemonStration() { }
public delegate void DisplayStringDelegate(string strmes);
}
在上面的示例代码中,我们定义了一个委托示例类DelegateDemonStration,在DelegateDemonStration的内部我们定义了上一节中讲到的委托的类型DisplayStringDelegate,
在这里先不谈DisplayStringDelegate它定义签名类型,先来谈谈它到底是什么样的存在。
我们来看一下代码:
/// <summary>
/// 委托示例类
/// </summary>
public class DelegateDemonStration
{
public DelegateDemonStration() { }
public class DisplayStringDelegate : MulticastDelegate
{
public DisplayStringDelegate(object @object, IntPtr method){}
public virtual IAsyncResult BeginInvoke(string strmes, AsyncCallback callback, object @object);
public virtual void EndInvoke(IAsyncResult result);
public virtual void Invoke(string strmes);
}
}
当我们定义好一个委托类型的时候,在运行时C#编译器把【public delegate void DisplayStringDelegate(string strmes);】
编译为【public class DisplayStringDelegate : MulticastDelegate】
所以,各位客官只要记住 在你定义一个委托类型的时候实际上你是定义了一个类
- 委托实例是函数指针
先让我们来看一下这一小节所要用到的示例代码(所用到的对象类型还是上一小节的内容):
DisplayStringDelegate disstrdele = new DisplayStringDelegate(new ManyMethodClass().InstanceMethod);
disstrdele += ManyMethodClass.StaticMethod;//这里是委托类型推断 绑定函数的一种方式 几种方式可以自行百度
disstrdele += new DisplayStringDelegate(ManyMethodClass.StaticMethod);
1.第一步 在我们执行DisplayStringDelegate disstrdele = new DisplayStringDelegate(new ManyMethodClass().InstanceMethod);的时候,disstrdele实例是如下图一样:
2.第二步 当我们继续执行代码 disstrdele += ManyMethodClass.StaticMethod;的时候,请再来看图:
这是disstrdele多指向了一个函数地址,而它的内部实现并不是外表看起来这样简单的:
这里简要的说一下执行第二步的时候
L_0012:是将第一步的disstrdele实例压入栈中
L_0013:将一个空引用压入栈中
L_0014:加载ManyMethodClass.StaticMethod函数地址
L_001a:实例化DisplayStringDelegate委托类型,假如它叫A
L_001f:将disstrdele和A合并
L_0024:将合并好的值转换成DisplayStringDelegate类型,并且存入L_0013中
L_0029:将L_0013赋值到disstrdele实例
(以上纯属个人理解,如有偏差请帮忙纠正,谢谢)
3.第三步 当我们继续执行代码disstrdele += new DisplayStringDelegate(ManyMethodClass.StaticMethod);的时候,过程和第二步相同:
终上所述,委托实例都会指向一个函数地址,当然喽合并过后新的委托实例宁当别论,所以 委托实例是函数指针 或者 委托实例是函数指针列表
1.3 委托实例的调用
我们来看调用的代码:
disstrdele("Hello Word");
这里的内容是接着上一小节的内容继续讲的,拆分开来讲是为了让大家能看的更清楚。
看一下示意图吧,
从这里就可以看出来了,虽然disstrdele 实例是合并后的委托实例,它的屁股上挂上了好多函数地址,但是执行这样函数的入口还只是一个,那就是Delegate.Invoke(string),
如果有人要问它的Invoke(string)内部是怎么实现的,暂时回答不了,因为具体的代码是动态生成的吧,不过我们可以自己猜想或者想象一下它是怎么实现的。
在这里就不多说了。
看了以上的内容能大概的知道或者分清一些概念性的东西。
这里本人只是讲了一把剑是由铁铸成的,可以用来切割、刺、劈、砍,至于这把剑怎么用就因人而异了。
2. 事件
2.1 事件是什么?
这一章我们来学习一下事件
照旧我们先来看一下示例代码:
public class EventDomeStration
{
public EventDomeStration() { }
/// <summary>
/// 定义好的一个示例
/// </summary>
public event DisplayStringDelegate DisplayStringEventHandler;
}
在上面的代码中,我们定义了一个事件DisplayStringEventHandler,而在它名称前面的是一个DisplayStringDelegate委托类型(就是我们上一节所说的委托)。
就对于它而言来看一下MSIL,看看它究竟是什么样的:
.class public auto ansi beforefieldinit EventDomeStration extends [mscorlib]System.Object
{
.field private class DelegateCaseAndEventCase.DisplayStringDelegate DisplayStringEventHandler
.event DelegateCaseAndEventCase.DisplayStringDelegate DisplayStringEventHandler
{
.addon instance void DelegateCaseAndEventCase.EventDomeStration::add_DisplayStringEventHandler(class DelegateCaseAndEventCase.DisplayStringDelegate)
.removeon instance void DelegateCaseAndEventCase.EventDomeStration::remove_DisplayStringEventHandler(class DelegateCaseAndEventCase.DisplayStringDelegate)
}
}
从这里可以看到,定义好的一个事件就是一个私有(DisplayStringDelegate委托类型)的字段加上一个事件访问器,也就是相当于C#代码的这样:
public class EventDomeStration
{
public EventDomeStration() { }
private DisplayStringDelegate displaystringdele;
public event DisplayStringDelegate DisplaystringEventHandler
{
add
{
displaystringdele += value;
}
remove
{
displaystringdele -= value;
}
}
}
在这里本人对事件的定义是:
事件就是所在对象里的属性,而属性的类型是委托类型,它是负责架设与外部对象即时通讯(传递消息)的桥梁,桥梁本身就是委托。
2.2 事件的使用
出门在外务工,难免要租房子住,每次找房子是件头疼的事请各位客官一起来看一下,就拿这个来举个例子。
先定义一个委托:public delegate void 消息反馈(string 反馈房子信息);
首先得有一个中介,暂且叫它为房产中介1, 来看一下它的内部定义:
public class 房产中介1
{
public 房产中介1() { }
public 房产中介1(string 具体要求)
{
房源信息处理(具体要求);
}
public event 消息反馈 消息通知;
public string 客户要求的信息_1 = string.Empty;
private void 房源信息处理(string 客户要求的信息)
{
//逻辑处理
//假如是有客户需要的 则通知客户
if (消息通知 != null)
{
消息通知("有房子,什么样的,信息等等");
}
客户要求的信息_1 = 客户要求的信息;
//逻辑处理要是没有 把信息移交给了中介2
房产中介2 中介2 = new 房产中介2(this);
}
public void 其它中介消息通知(string 房子信息)
{
if (消息通知 != null)
{
消息通知(房子信息);
}
}
}
中介有了,那现在我想要开始租房子怎么办?没关系,找中介。
首先先把“我”定义出来:
public class 我
{
//比如我要租房子
public 我(){ }
public void 我要租房子(string 具体的要求)
{
//找的是房产中介1
房产中介1 中介1 = new 房产中介1(具体的要求);
中介1.消息通知 += new 消息反馈(中介1_消息通知);
}
void 中介1_消息通知(string 房子信息)
{
//我可以从【房子信息】中知道是否有有合适的房子,如果有得话,是什么样的
}
}
public class 房产中介2
{
public string 客户要求信息 = string.Empty;
public 房产中介2() { }
public 房产中介2(房产中介1 中介1)
{
房源信息处理(中介1);
}
private void 房源信息处理(房产中介1 中介1)
{
//逻辑处理
//判断是否有满足 ->中介1.客户要求的信息_1值条件的房源
//如果有
中介1.其它中介消息通知("房子有的,房子的信息等等");
}
}
上面定义了 我、房产中介1、房产中介2,现在 我 要找房子了
我 me = new 我();
me.我要租房子("有床就行");
好了,“我”已经把信息发布出去了,现在就坐等房产中介1的通知了。
因为事件只能是对象本身内部触发,这个设计是合理,为什么不能用委托,委托也可以实现同样的功能啊?
假如用了委托,这个例子的意思就是“我”可以控制房产中介1有没有找到房子信息,这个是不符合常理的。
因为“我”是找的房产中介1,房产中介1根据“我”的要求没找到,把这个信息交给了房产中介2,让房产中介2帮忙找找,然后中房产中介2找到了,
但是中房产中介2并不能直接通知“我”,如果可以直接通知的话,这样“我”会告房产中介1侵犯客户隐私,
所以只能是房产中介2告诉房产中介1找到了【也就是代码:房产中介1.其它中介消息通知("房子有的,房子的信息等等");】,然后再由房产中介1来通知“我”。
C#之委托与事件的更多相关文章
- .NET面试题系列[7] - 委托与事件
委托和事件 委托在C#中具有无比重要的地位. C#中的委托可以说俯拾即是,从LINQ中的lambda表达式到(包括但不限于)winform,wpf中的各种事件都有着委托的身影.C#中如果没有了事件,那 ...
- .NET基础拾遗(4)委托、事件、反射与特性
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...
- [转载]C#深入分析委托与事件
原文出处: 作者:风尘浪子 原文链接:http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html 同类链接:http://www.c ...
- [转载]C#委托和事件(Delegate、Event、EventHandler、EventArgs)
原文链接:http://blog.csdn.net/zwj7612356/article/details/8272520 14.1.委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托.委 ...
- C#委托与事件
一.在控制台下使用委托和事件 我们都知道,C#中有"接口"这个概念,所谓的"接口"就是定义一套标准,然后由实现类来具体实现其中的方法,所以说"接口,是 ...
- C#委托与事件的简单使用
前言:上一篇博文从原理和定义的角度介绍了C#的委托和事件.本文通过一个简单的小故事,来说明C#委托与事件的使用方法及其方便之处. 在阅读本文之前,需要你对委托和事件的基本概念有所了解.如果你是初次接触 ...
- [ASP.NET MVC 大牛之路]02 - C#高级知识点概要(1) - 委托和事件
在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...
- .NET委托和事件
.net学习之委托和事件 1.什么是委托 通俗的说:委托就是一个能够存储符合某种格式(方法签名)的方法的指针的容器 上传图片: 2.委托语法 准备一个方法:string Hello(string ...
- C#委托和事件
委托和事件都可以用来调用跟自己方法签名一样的方法,两者在使用中主要有以下区别: 委托和事件没有可比性,因为委托是类型,事件是对象: 委托可以在声明它的类外部进行调用,而事件只能在类的内部进行调用: 委 ...
随机推荐
- Jquery便利对象
xhr=[object object] $.each(xhr, function (key, val) { alert(key + '=' + val); ...
- JAVA运行时问题诊断-工具应用篇
该BLOG内容是之前在部门组织讨论运行时问题时自己写的PPT内容,内容以点带面,主要是方便以后自己回顾查看. 大纲包括:1.运行时问题分类 2.服务器自带工具 3.其他工具 4.例子 5.实际情况 运 ...
- 【My Life】写在年末, 我的2013
[My Life]写在年末, 我的2013 SkySeraph Dec. 30 2013 Email:skyseraph00@163.com 好久没写博客了, 遗忘的历史,遗忘了自我... 岁月拾回 ...
- KeyedPriorityQueue
// <copyright file="KeyedPriorityQueue.cs" company="Microsoft">Copyright ( ...
- OpenCv遍历图像小结
参考:http://www.cnblogs.com/ronny/p/opencv_road_2.html http://blog.csdn.net/xiaowei_cqu/article/detail ...
- Web Applicationservlet,cookie,session
Web Application简介: Web Application NameWEB-INFweb.xml 该web application的配置文件lib 该web application用到的依赖 ...
- [spring源码学习]三、IOC源码——自定义配置文件读取
一.环境准备 在文件读取的时候,第9步我们发现spring会根据标签的namespace来选择读取方式,联想spring里提供的各种标签,比如<aop:xxx>等应该会有不同的读取和解析方 ...
- 转:WaitForSingleObject()函数、WaitForMultipleObject()函数
http://blog.csdn.net/xiaobai1593/article/details/6672193 在多线程下面,有时候我们会希望等待某一线程完成了再继续做其他事情,要实现这个目的,可以 ...
- linux菜鸟日记(2)
ntp服务的安装与配置: 安装ntp服务的过程比较简单首先你需要挂载光盘然后安装ntp服务如果配置了本地yum源可以直接使用光盘中的资源进行本地yum的安装,如果没有就使用rpm包进行安装. 由于我已 ...
- 关于用display:table让元素居中的小结
我们都知道让元素垂直居中有一种简单的方法:给需要居中的元素用一个父级包起来,并给它设置样式:display:table:同时给这个父级设置好高度:再给需要居中的元素一个display:table-ce ...