委托、事件和Lambda
一、委托 delegate
1.在.Net平台下,委托类型用来定义和响应应用程序中的回调。事实上,.Net委托类型是一个类型安全的对象,指向可以以后调用的其他方法,.Net委托是内置支持
多路广播和异步方法调用的对象。.Net委托是类型安全的,如果将一个不“匹配模式”的方法传入委托,将会收到编译器错误。
2.委托类型包含3个重要的信息:
(1)它所调用的方法的名称;
(2)该方法的参数(可选);
(3)该方法的返回值(可选)。
.Net委托既可指向静态方法,也可以指向实例方法。
3.定义委托类型:public delegate int BinaryOp(int x, int y);
经过反编译:委托类型BinaryOp自动产生一个派生自System.MulticastDelegate(这是一个抽象类)的密封类,并生产3个方法:
(1)public virtual int Invoke(int x, int y);它被用来以同步方式调用委托对象维护的每个方法。
(2)public virtual IAsyncResult BeginInvoke(int x, int y, AsyncCallback callback, object @object);以异步方式调用委托对象维护的方法。
(3)public virtual int EndInvoke(IAsyncResult result);
4.委托还可以指向包含任意数量out或ref参数(以及用params关键字标记的数组参数)的方法。
5.System.MulticastDelegate 和 System.Delegate
我们永远不会直接派生自这些基类,如果我们使用delegate关键字,就间接创建了一个类,这个类“是” MulticastDelegate。
所有委托类型都共有的核心成员:
Method:此属性方法MethodInfo对象,用以表示委托维护的静态方法的详细信息。
Target:如果方法调用是定义在对象级别的(而不是静态方法),Target返回表示委托维护的方法的对象。如果Targe返回值为null,调用的方法是一个静态方法。
Combine():此静态方法给委托维护的列表添加一个方法。在C#中,使用重载+=操作符作为简化符号调用此方法。
GetInvocationList():此方法返回一个System.Delegate类型的数组,其中数组中的每个元素都表示一个可调用的特定方法。
Remove(),RemoveAll():这些静态方法从调用列表中移除一个(或所有)方法,在C#中,Remove()方法可通过使用重载-=操作符来调用。
6.使用委托发送对象状态通知
(1)定义将通知发送给调用者的委托类型。
(2)声明类中每个委托类型的成员变量。
(3)在类上创建辅助函数使调用者能指定由委托成员变量保存的方法。(注册函数)
(4)在类内部的某个方法中调用委托的方法列表。
示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApplication6
{
class Program
{
static void Main(string[] args)
{
DoSomething d = new DoSomething("打地基");
d.RegisterWorkEngineHandler(WorkEvent); for (int i = ; i <= ; i++)
{
d.Work(i);
} Console.ReadKey();
} static void WorkEvent(string msg)
{
Console.WriteLine(msg);
}
} class DoSomething
{
public string WorkName { get; set; } public DoSomething(string workname)
{
this.WorkName = workname;
} public void Work(int step)
{
this.handler(string.Format("{0}工作:正在做第{1}步事情...", this.WorkName, step));
} // 定义委托类型
public delegate void WorkEngineHandler(string msg); // 声明私有的委托类型变量
private WorkEngineHandler handler; // 注册委托对象
public void RegisterWorkEngineHandler(WorkEngineHandler handler)
{
this.handler = handler;
}
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApplication6
{
class Program
{
static void Main(string[] args)
{
DoSomething d = new DoSomething("打地基");
d.RegisterWorkEngineHandler(WorkEvent); for (int i = ; i <= ; i++)
{
d.Work(i);
} Console.ReadKey();
} static void WorkEvent(string msg)
{
Console.WriteLine(msg);
}
} class DoSomething
{
public string WorkName { get; set; } public DoSomething(string workname)
{
this.WorkName = workname;
} public void Work(int step)
{
this.handler(string.Format("{0}工作:正在做第{1}步事情...", this.WorkName, step));
} // 定义委托类型
public delegate void WorkEngineHandler(string msg); // 声明私有的委托类型变量
private WorkEngineHandler handler; // 注册委托对象
public void RegisterWorkEngineHandler(WorkEngineHandler handler)
{
this.handler = handler;
}
} }
7.方法组转换语法:该特性允许我们在调用以委托作为参数的方法时直接提供方法的名称,而不是创建委托对象。
8.委托协变:因为委托是安全类型,它们不遵守继承的基本规则。协变允许我们构建一个委托,能指向返回类及相关继承体系的方法。
逆变:允许我们创建一个委托,指向多个方法,方法的参数是存在传统继承关系的对象。
9.泛型委托:通过类型参数来构建
public delegate void MyGenericDelegate<T>(T arg);
在不使用泛型的情况下模拟泛型委托:public delegate void MyDelegate(object arg);尽管这样可以把任何类型的数据发送到委托目标,但是会因此
失去类型安全并且可能还会有装箱/拆箱损失
二、事件 event
从头使用委托会有一些重复代码:定义委托,声明必要的成员变量以及创建自定义的注册/注销方法来保存封装等。
1.为了简化自定义方法的构建来为委托调用列表增加和删除方法,C#提供了event关键字。在编译器处理event关键字的时候,它会自动提供注册和注销方法以及委托类型
任何必要的成员变量。这些委托成员变量总是声明为私有的,因此不能直接从触发事件的对象访问它们。
2.定义一个事件分为两个步骤:首先,我们需要定义一个委托类型,它包含在事件触发时将要调用的方法。其次,通过C# evnet关键字用相关委托声明这个事件。
3.C#事件事实上会扩展为两个隐藏的公共方法,一个带add_前缀,另一个带remove_前缀,前缀后面是C#事件的名称。
4..Net基础类库底层委托的第一个参数是一个System.Object,第二个参数是派生自System.EventArgs的子类型。System.Object参数表示一个对发送事件的对象的引用,
第二个参数则表示与该事件相关的信息。
5.泛型EventHandler<T>委托
由于很多自定义委托接受object作为第一个参数,EventArgs派生类型作为第二个参数,我们可以通过使用泛型EventHandler<T>类型来进一步简化
public event EventHandler<MyEventArgs> Exploded;
6.按钮的单击事件
// 摘要:
// 表示将处理不包含事件数据的事件的方法。
//
// 参数:
// sender:
// 事件源。
//
// e:
// 不包含任何事件数据的 System.EventArgs。
[Serializable]
[ComVisible(true)]
public delegate void EventHandler(object sender, EventArgs e); //
// 摘要:
// 在单击控件时发生。
public event EventHandler Click; this.button1.Click += new System.EventHandler(this.button1_Click);
private void button1_Click(object sender, EventArgs e)
{ }
三、Lambda表达式
1.手工定义一个由委托对象调用的方法显得有点繁琐,现在可以在事件注册时直接将一个委托与一段代码相关联,这种代码的正式名称称为匿名方法。
t.SomeEvent += delegate(参数){};
2.匿名方法不能访问定义方法中的ref或out参数;匿名方法中的本地变量不能与外部方法中的本地变量重名;匿名方法可以访问外部类作用域中的实例变量(或静态变量)。
3.Lambda表达式只是用更简单的方法来写匿名方法,彻底简化了对.Net委托类型的使用。
4.Lambda表达式规则:首先定义一个参数列表(0个或多个),“=>”标记紧随其后,然后就是处理这些参数的语句。
委托、事件和Lambda的更多相关文章
- 9、委托、事件、Lambda
开始 关于委托,肯定是要有问题的. 第一个问题,委托用来干什么? 看.net中的表述:在.net平台下,委托类型用来定义和相应应用程序中的回调.(回调?处理内存中两个实体双向通信的一种技术.) 第 ...
- 委托,事件,lambda表达式
开篇说明三个点: 委托是一种类型 事件是委托的实例 lambda表达式是一个方法(匿名方法) [未完待续]
- C# ~ 从 委托事件 到 观察者模式 - Observer
委托和事件的部分基础知识可参见 C#/.NET 基础学习 之 [委托-事件] 部分: 参考 [1]. 初识事件 到 自定义事件: [2]. 从类型不安全的委托 到 类型安全的事件: [3]. 函数指针 ...
- Unity C#笔记 委托&事件
C#的委托与事件搭配,即是观察者模式的一种实现. 因为观察者模式的原理很易懂,不作多讲,本文纯粹用于记录语法. delegate(委托) //声明没有参数,没有返回值的委托类型XXXX public ...
- Delegate,Action,Func,匿名方法,匿名委托,事件 (转载)
Delegate,Action,Func,匿名方法,匿名委托,事件 (转载) 一.委托Delegate 一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本 ...
- C#委托,事件理解入门 (译稿)
原文地址:http://www.codeproject.com/Articles/4773/Events-and-Delegates-Simplified 引用翻译地址:http://www.cnbl ...
- 关于ios使用jquery的on,委托事件失效
$('.parents').on("click",'.child',function(){}); 类似上面这种,在ios上点击"child"元素不会起作用,解决 ...
- Observer设计模式中-委托事件-应用在消息在窗体上显示
Observer设计模式:监视者模式.在类中的方法中处理的结果或者消息通过事件委托 的方式发送给主窗体. 因为在其它类中直接访问主窗体类,显示内容是不能直接调用控件赋值的,当然也有别的类似查阅控件名, ...
- Asp.net用户控件和委托事件
在Asp.net系统制作过程中,门户类型的网站,我们可以用DIV+CSS+JS+Ajax全部搞定,但是一旦遇到界面元素比较复杂的时候,还是UserControl比较方便一些,各种封装,各种处理,然后拖 ...
- jQuery里面的普通绑定事件和on委托事件
以click事件为例: 普通绑定事件:$('.btn1').click(function(){}绑定 on绑定事件:$(document).on('click','.btn2',function(){ ...
随机推荐
- 大数据实践:ODI 和 Twitter (一)
本文利用twitter做为数据源,介绍使用Oracle大数据平台及Oralce Data Integrator工具,完成从twitter抽取数据,在hadoop平台上处理数据,并最终加载到oracle ...
- Lua 多维表的遍历中的赋值
说到Lua的遍历将要使用到循环:先说遍历再说循环: 遇到这样类似结构的一个table Data={ []={p1=,pa={,,}}, []={p1=,pa={,,}}, []={p1=,pa={,, ...
- css3圆角边框,边框阴影
border-radius向元素添加圆角边框,css3中的.IE9+ chrome safari5+ firefox4+ 现在都支持.可以向input div等设置边框.与border相似,可以四个角 ...
- JSON (仅限本地)
<script type="text/javascript"> setInterval(function() { $("#content").loa ...
- .NET Framework4.0 下的多线程
一.简介 在4.0之前,多线程只能用Thread或者ThreadPool,而4.0下提供了功能强大的Task处理方式,这样免去了程序员自己维护线程池,而且可以申请取消线程等...所以本文主要描述Tas ...
- 将python2.7+django1.10部署到SAE上
首先我想说的是我为什么选择SAE呢?本人学生一枚,没钱.然后sae好像又有免费的一定限额,所以我就选了它. 期间曲折颇多,实在不是三言两语所能道情的.各种百度,谷歌,最后所幸成功了,幸哉! 主要参考了 ...
- .net控件事件中的Sender
private void button2_Click(object sender, RoutedEventArgs e) { } 最近看WPF内容,回顾下.net大家天天都在用,却不是十分关注的一个对 ...
- char const*, char*const, const char *const的区别
C++标准规定,const关键字放在类型或变量名之前等价的.所以,const char*和 char const*是一样的. const char* //常量指针---指向常量的指针----指针指 ...
- MongoDB仲裁节点的理解以及memcached,zookeeper,redis,故障恢复方案思考.
在进行副本集部署时我们会添加一个或多个仲裁节点,仲裁节点不用于备份数据,由于它职责的职责是负责选举主节点,所以对硬件没有太高要求,可以将它部署在单独的服务器上,这个服务器可以是监听服务器,也可以部署在 ...
- job不自动运行解决方法
一.plsql.新建命令窗口 用查询语句: show parameter job_queue_processes 看看job_queue_processes的值 如果你的job很多那么将这个值设大,5 ...