委托、事件和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(){ ...
随机推荐
- Oracle删除表主键语句
删除无名主键语句: SELECT * FROM USER_CONS_COLUMNS WHERE TABLE_NAME = '表名'; ALTER TABLE 表名 DROP CONSTRAINT 主键 ...
- 如何在linux中配置PHP环境
yum -y install httpd php mysql mysql-server php-mysql//安装mysql扩展yum -y install mysql-connector-odbc( ...
- MHA学习笔记
MHA是一款开源的MySQL高可用程序,为MySQL主从复制架构提供了节点故障转移功能,当 master发生故障时MHA会自动提升拥有最新数据的slave节点成为新的主节点,还提供了master节 点 ...
- SequoiaDB创始人:比MongoDB领先一到两年 打造企业级NoSQL数据库
CSDN.NET 这几年来, NoSQL数据库凭借其易扩展.高性能.高可用.数据模型灵活等特色吸引到了大量新兴互联网公司的青睐,包括国内的淘宝.新浪.京东商城.360.搜狗等都已经在局部尝试NoS ...
- 关键字替换排除HTML标签属性字符
解决办法: 1.打开文件e/class/functions.php 2.找到函数 ReplaceKey($newstext,$classid=0) 3.找到替换代码 if(STR_IREPLACE) ...
- 刀哥多线程笔记之gcd-02-block
block 概念 block 是 C 语言的 是一种数据类型,可以当作参数传递 是一组预先准备好的代码,在需要的时候执行 动画 block 回顾 self.demoView.center = CGPo ...
- DB2物化表
DB2物化查询表(MQT)是DB2数据库中一类特殊的表 物化表和视图的区别 物化表是一个查询结果集,视图是一个SQL语句. 以下是一个简单例子(说明物化表) 1.创建表,插入测试数据 ----创建表 ...
- Java中HashMap,LinkedHashMap,TreeMap的区别[转]
原文:http://blog.csdn.net/xiyuan1999/article/details/6198394 java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类 ...
- outlook配置
有时打开outlook报错.步骤如下: 一.打开控制面板-邮件-电子邮件账户-新建 二.具体设置如下: 三.点第二步上的“其他设置(M)”.做发送服务器.
- python中的小技巧
1.求1~100以内的素数 prime=filter(lambda x: not [x%i for i in range(2,x) if x%i==0], range(2,101))#列表推导,一行搞 ...