委托和事件[delegate and event]_C#
委托和事件:
1. 委托:一个能够表示方法的数据类型;它将方法作为对象封装起来,允许在运行时间接地绑定一个方法调用。
2. 声明委托数据类型:
public delegate bool GreaterThanHandler(int first , int second);
3. 委托的实例化:
为了实例化委托,需要和委托类型自身的签名对应的一个方法;实例时不必用new来实例化该类的实例,直接传递名称即可[C#2.0新语法]。 如:
GreaterThanHandler a = 方法名;
C#2.0以前的语法:
GreaterThanHandler a = new GreaterThanHandler (方法名) ;
4. 匿名方法:
匿名方法没有实际方法声明的委托实例,它们的定义是直接内嵌在代码中的。如:
GreaterThanHandler a = delegate(int first , int second){return (first<second);};
5. 委托的内部机制:
C#将所有委托定义成间接派生于System.Delegate ,这个类有两个属性:(1)MethodInfo(System.Reflection.MethodInfo类型): 定义了一个特定方法签名(包括方法的名称、参数和返回类型) (2)Target(Object类型):对象实例,其中包含了要调用的方法。
6. multicast委托:
一个委托变量可以引用一系列委托,在这一系列委托中,每个委托都顺序指向一个后续的委托,从而形成一个委托链, 或者称为multicast委托。
Publish-subscribe(发布-订阅)模式: 它对应这样一种情形:需要将单一的事件通知(比如对象状态发生的一个变化)广播给多个订阅者(subscriber).
7. 使用委托来编写Observer模式(publish-subscribe模式):
例: 一个加热器(Heater)和一个冷却器(Cooler)连接到同一个温度计(thermostat) 上。为了控制加热器和冷却器的打开和关闭,要向它们通知温度的变化,温度计将温度的变化发布(publish)给多个订阅者-也就是加热器和冷却器。
看一段代码:〔注意①②③④个步骤:〕
using System;
namespace test
{
//定义订阅者
class Cooler //冷却器
{
private float _Temperature; //启动设备所需的温度
public float Temperature //属性
{
get { return _Temperature; }
set { _Temperature = value; }
}
public Cooler(float temperature) //构造器
{
Temperature = temperature;
}
//③在事件订阅者中定义事件处理程序
public void OnTemperatureChanged(float newTemperature) //订阅者方法
{
if (newTemperature > Temperature)
{
Console.WriteLine("Cooler:On");
}
else
{
Console.WriteLine("Cooler:Off");
}
}
}
class Heater //加热器
{
private float _Temperature; //启动设备所需的温度
public float Temperature //属性
{
get { return _Temperature; }
set { _Temperature = value; }
}
public Heater(float temperature) //构造器
{
Temperature = temperature;
}
//③在事件订阅者中定义事件处理程序
public void OnTemperatureChanged(float newTemperature) //订阅者方法
{
if (newTemperature < Temperature)
{
Console.WriteLine("Heater:On");
}
else
{
Console.WriteLine("Heater:Off");
}
}
}
//定义发布者
class Thermostat
{
public delegate void TemperatureChangeHandler(float newTemperature); //定义委托数据类型,注意这是一个嵌套类;
//①在事件发行者中定义一个事件
private TemperatureChangeHandler _OnTemperatureChange; //存储订阅者列表,只需一个委托字段即可存储所有订阅者(委托链)。
public TemperatureChangeHandler OnTemperatureChange
{
get { return _OnTemperatureChange; }
set { _OnTemperatureChange = value;}
}
//设置由温度计报告的当前温度值并触发事件
private float _CurrentTemperature;
public float CurrentTemperature
{
get { return _CurrentTemperature; }
set
{
if (value != CurrentTemperature)
{
_CurrentTemperature = value;
//②在事件发行者中触发事件
TemperatureChangeHandler localOnChange = OnTemperatureChange;
if (localOnChange != null) //调用一个委托之前,要检查它的值是不是空值。
{
localOnChange(value); //触发事件
}
}
}
}
}
//连接发布者和订阅者
class Program
{
static void Main(string[] args)
{
Thermostat thermostat = new Thermostat();
Heater heater = new Heater(60);
Cooler cooler = new Cooler(80);
string temperature;
//④向事件发行者订阅一个事件
thermostat.OnTemperatureChange += heater.OnTemperatureChanged; //向OnTemperatureChange注册订阅者;
thermostat.OnTemperatureChange += cooler.OnTemperatureChanged;
Console.WriteLine("输入温度:");
temperature = Console.ReadLine();
thermostat.CurrentTemperature = int.Parse(temperature);
Console.ReadLine();
}
}
}
8. 委托运算符:
+= , -= ; + , - ;
注:使用赋值运算符,会清除之前的所有订阅者,并允许使用新的订阅者替换它们。
9. multicast委托的内部机制:
->delegate关键字是派生自System.MulticastDelegate的一个类型的别名;MulticastDelegate类包含一个对象引用和一个方法指针。当向一个multicast委托添加一个方法时,MulticastDelegate类会创建委托类型的一个新实例,在新实例中为新增的方法存储对象引用和方法指针,并在委托实例列表中添加新的委托实例作为下一项。MulticastDelegate类维护着由多个Delegate对象构成的一个链表。
但是有两个问题需要解决:
1) 错误处理:假如一个订阅者引发了一个异常,链中的后续订阅者就接收不到通知;
2) 方法返回值和传引用:因为调用一个委托,就有可能造成将一个通知发送给多个订阅者,假如订阅者会返回值,就不确定到底该使用哪个订阅者的返回值。
以上两个问题都可以用GetInvocationList()方法遍历每个委托调用列表来处理。
10. 事件:
事件的目的:
1) event关键字的目的就是提供额外的封装,避免你不小心地以取消其他订阅者;
2) 事件确保只有包容类才能触发一个事件通知;
总言之:event关键字提供了必要的封装来防止任何外部类发布一个事件或取消之前的订阅者。
下面这段代码对上述代码进行了修改:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace test
{
//定义订阅者
class Cooler //冷却器
{
private float _Temperature; //启动设备所需的温度
public float Temperature //属性
{
get { return _Temperature; }
set { _Temperature = value; }
}
public Cooler(float temperature) //构造器
{
Temperature = temperature;
}
//③在事件订阅者中定义事件处理程序
public void OnTemperatureChanged(object sender, Thermostat.TemperatureArgs newTemperature) //订阅者方法
{
if (newTemperature.NewTemperature > Temperature)
{
Console.WriteLine("Cooler:On");
}
else
{
Console.WriteLine("Cooler:Off");
}
}
}
class Heater //加热器
{
private float _Temperature; //启动设备所需的温度
public float Temperature //属性
{
get { return _Temperature; }
set { _Temperature = value; }
}
public Heater(float temperature) //构造器
{
Temperature = temperature;
}
//③在事件订阅者中定义事件处理程序
public void OnTemperatureChanged(object sender,Thermostat .TemperatureArgs newTemperature) //订阅者方法
{
if (newTemperature.NewTemperature < Temperature)
{
Console.WriteLine("Heater:On");
}
else
{
Console.WriteLine("Heater:Off");
}
}
}
//定义发布者
class Thermostat
{
public class TemperatureArgs : System.EventArgs
{
public TemperatureArgs(float newTemperature)
{
NewTemperature = newTemperature;
}
public float NewTemperature
{
get { return _newTemperature; }
set { _newTemperature = value; }
}
private float _newTemperature;
}
//①在事件发行者中定义一个事件
public delegate void TemperatureChangeHandler(object sender, TemperatureArgs newTemperature); //定义委托数据类型,注意这是一个嵌套类;
public event TemperatureChangeHandler OnTemperatureChange;
//public TemperatureChangeHandler OnTemperatureChange //存储订阅者列表,只需一个委托字段即可存储所有订阅者(委托链)。
//{
// get { return _OnTemperatureChange; }
// set { _OnTemperatureChange = value; }
//}
//private TemperatureChangeHandler _OnTemperatureChange;
//设置由温度计报告的当前温度值并触发事件
public float CurrentTemperature
{
get { return _CurrentTemperature; }
set
{
if (value != CurrentTemperature)
{
_CurrentTemperature = value;
//②在事件发行者中触发事件
if (OnTemperatureChange != null)
{
OnTemperatureChange(this, new TemperatureArgs(value));
}
}
}
}
private float _CurrentTemperature;
}
//连接发布者和订阅者
class Program
{
static void Main(string[] args)
{
Thermostat thermostat = new Thermostat();
Heater heater = new Heater(60);
Cooler cooler = new Cooler(80);
string temperature;
//④向事件发行者订阅一个事件
thermostat.OnTemperatureChange += heater.OnTemperatureChanged; //向OnTemperatureChange注册订阅者;
thermostat.OnTemperatureChange += cooler.OnTemperatureChanged;
Console.WriteLine("输入温度:");
temperature = Console.ReadLine();
thermostat.CurrentTemperature = int.Parse(temperature);
//thermostat.OnTemperatureChange(44);
Console.ReadLine();
}
}
}
委托和事件[delegate and event]_C#的更多相关文章
- 第一章、C#委托和事件(Delegate、Event、EventHandler、EventArgs)
第一章.C#委托和事件(Delegate.Event.EventHandler.EventArgs) 分类: 学习笔记-C#网络编程2012-12-08 14:10 7417人阅读 评论(3) 收藏 ...
- [转载]C#委托和事件(Delegate、Event、EventHandler、EventArgs)
原文链接:http://blog.csdn.net/zwj7612356/article/details/8272520 14.1.委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托.委 ...
- 委托与事件--delegate&&event
委托 访问修饰符 delegate 返回值 委托名(参数); public delegate void NoReturnNoPara(); public void NoReturnNoParaMeth ...
- CS中委托与事件的使用-以Winform中跨窗体传值为例
场景 委托(Delegate) 委托是对存有某个方法的引用的一种引用类型变量. 委托特别用于实现事件和回调方法. 声明委托 public delegate int MyDelegate (string ...
- Delegate(委托与事件)
Delegate可以当它是一个占位符,比如你在写代码的时候并不知道你将要处理的是什么.你只需要知道你将要引入的参数类型和输出类型是什么并定义它即可.这就是书本上所传达的方法签名必须相同的意思. 系统自 ...
- 事件[event]_C#
事件(event): 1. 事件是类在发生其关注的事情时用来提供通知的方式.例如,封装用户界面控件的类可以定义一个在单击该控件时发生的事件.控件类不关心单击按钮时发生了什么,但它需要告知派 ...
- 转载: jQuery事件委托( bind() \ live() \ delegate()) [委托 和 绑定的故事]
转载:http://blog.csdn.net/zc2087/article/details/7287429 随着DOM结构的复杂化和Ajax等动态脚本技术的运用,事件委托自然浮出了水面.jQuery ...
- C#基础篇 - 理解委托和事件
1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托是C#中类型安全的,可以订阅一个或多个具有相同签名方法的函数指针.简单理解,委托是一种可以把函数当做参数传递的类型.很多情况下,某 ...
- .NET面试题系列[7] - 委托与事件
委托和事件 委托在C#中具有无比重要的地位. C#中的委托可以说俯拾即是,从LINQ中的lambda表达式到(包括但不限于)winform,wpf中的各种事件都有着委托的身影.C#中如果没有了事件,那 ...
随机推荐
- Codeforces GYM 100114 D. Selection 线段树维护DP
D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Descriptio ...
- HttpClient 设置代理方式
HttpClient httpClient = new HttpClient(); //设置代理服务器的ip地址和端口 httpClient.getHostConfiguration().setPro ...
- httpclient发送request请求时设置header和timeout
package com.xxx.xxx.common; import java.io.BufferedReader; import java.io.InputStreamReader; import ...
- JAVA反射机制学�
JAVA反射机制:对于随意一个类,都可以知道这个类的全部属性和方法:对于随意一个对象,都可以调用它的随意一个方法和属性:这样的动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. J ...
- Jordan Lecture Note-11: 典型相关分析(Canonical Correlation Analysis, CCA).
典型相关分析 (一)引入 典型相关分析(Canonical Correlation Analysis)是研究两组变量之间相关关系的一种多元统计方法.他能够揭示出两组变量之间的内在联系. 我们知道,在一 ...
- 小白日记5:kali渗透测试之被动信息收集(四)--theHarvester,metagoofil,meltag,个人专属密码字典--CUPP
1.theHarvester theHarvester是一个社会工程学工具,它通过搜索引擎.PGP服务器以及SHODAN数据库收集用户的email,子域名,主机,雇员名,开放端口和banner信息. ...
- 实验-hadoop新增节点
关于hadoop新增节点网上的说法都有些差别,自己来实践一把 1.建立一个namenode一个datanode的集群 master:192.168.126.130 slave1:192.168.126 ...
- Android(java)学习笔记112:局部位置的内部类的介绍
1.局部内部类 /* 局部内部类 A:可以直接访问外部类的成员 B:在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能 面试题: 局部内部类访问局部变量的注意事项? A:局部 ...
- VS 无法启动程序
今天遇到这个问题网上找了很多资料,有很多人都遇到了这个问题,也有很多不同的答案,于是我们个答案都试了一遍都没有解决我这个问题的错误,于是就把控制面板中的打开功能和windows功能里面的Interne ...
- swift 中异常的处理方法
swift 中什么时候需要处理异常,在调用系统某个方法的时,该方法最后有一个throws 说明该方法会抛出异常,如果一个方法抛出异常,那么需要对该异常进行处理 swift 异常处理提供了三种方法 方式 ...