CLR VIA C#委托
1.什么是委托?委托就是一种回调函数的机制,将函数作为一个参数传递给其他对象,当该对象需要的时候调用委托来达到回调函数的目的。
通俗点的说法是:你将一件事情交给别人去做。例如你QQ里的自动回复,为了第一时间回复别人,你不可能一直守在QQ面前一有消息通知你就回复。所以你只好定义一个回复的方法,将这个方法交给QQ,告诉QQ当有消息过来的时候就调用你这个方法。QQ会给你这个方法传一个参数"对不起,我现在很忙balabala...",然后自动回复给对方
==========================================================我是解释的分割=========================================================
其实这里有两种情况,单就翻译而言,我觉得上面的解释比较符合“委托”的意思,就是你让别人帮你做你应该去做的事。而事件是一种特殊的委托,是别人通知你该做某事了,而做事的人还是你自己。实际委托是一个类型,把一个方法传递给委托会新创建一个对象,这个对象对方法进行包装。所以不管是哪种情况,都是委托对象调用方法。
=============================================================================================================================
2.其实委托很早就有了,说白了他只是函数指针在C#中的实现而已,不过在C#里他是类型安全的,并且可以顺序调用多个委托,支持静态方法和实例方法的调用。
3.正所谓无图无真相,没代码说JB,下面来看下委托实现的简单代码(以下代码来自CLRVIAC#)
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Reflection;
public sealed class Program {
public static void Main() {
DelegateIntro.Go();
}
}
internal sealed class DelegateIntro {
// 申明一个委托类型,他的实例(既然委托是一个类型,那么他其实会创建一个实例)引用一个方法,该方法接收一个Int32型的参数,返回空值
internal delegate void Feedback(Int32 value); public static void Go() {
StaticDelegateDemo();
} private static void StaticDelegateDemo() {
Console.WriteLine("----- Static Delegate Demo -----");
Counter(, , null);
Counter(, , new Feedback(DelegateIntro.FeedbackToConsole));
Counter(, , new Feedback(FeedbackToMsgBox));
Console.WriteLine();
}
private static void Counter(Int32 from, Int32 to, Feedback fb) {
for (Int32 val = from; val <= to; val++) {
if (fb != null)
fb(val);
}
}
private static void FeedbackToConsole(Int32 value) {
Console.WriteLine("Item=" + value);
}
private static void FeedbackToMsgBox(Int32 value) {
MessageBox.Show("Item=" + value);
}
}
以上是委托调用静态方法的例子,记住Counter这个函数接收3个参数,将遍历从from到to的值,并将它传递给FeedBack这个委托对象fb饮用的方法,然后调用该方法。
正如前面所说,这里创建了一个委托对象Feedback的一个实例
new Feedback(DelegateIntro.FeedbackToConsole)
,这个实例通过构造器传入的参数(方法签名)对方法进行了包装。然后将这个实例传入Counter函数中。需要注意的是这个委托实例包装的是一个静态方法,所以实例的内部并没有对其他对象的引用。
委托调用实例方法的例子如下
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Reflection; public sealed class Program {
public static void Main() {
DelegateIntro.Go();
}
}
internal sealed class DelegateIntro {
// 申明一个委托类型,他的实例(既然委托是一个类型,那么他其实会创建一个实例)引用一个方法,该方法接收一个Int32型的参数,返回空值
internal delegate void Feedback(Int32 value); public static void Go() {
InstanceDelegateDemo();
} private static void InstanceDelegateDemo() {
Console.WriteLine("----- Instance Delegate Demo -----");
DelegateIntro di = new DelegateIntro();
Counter(, , new Feedback(di.FeedbackToFile));
} private static void Counter(Int32 from, Int32 to, Feedback fb) {
for (Int32 val = from; val <= to; val++) {
// If any callbacks are specified, call them
if (fb != null)
fb(val);
}
} private void FeedbackToFile(Int32 value) {
StreamWriter sw = new StreamWriter("Status", true);
sw.WriteLine("Item=" + value);
sw.Close();
}
}
这里委托对象封装的是一个实例方法,所以内部会持有这个实例的一个引用,这个应用可以通过委托对象的target属性获得。
创建一个委托链的方式如下
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Reflection; public sealed class Program {
public static void Main() {
DelegateIntro.Go();
}
} internal sealed class DelegateIntro {
// 申明一个委托类型,他的实例(既然委托是一个类型,那么他其实会创建一个实例)引用一个方法,该方法接收一个Int32型的参数,返回空值
internal delegate void Feedback(Int32 value); public static void Go() {
ChainDelegateDemo1(new DelegateIntro());
ChainDelegateDemo2(new DelegateIntro());
} private static void ChainDelegateDemo1(DelegateIntro di) {
Console.WriteLine("----- Chain Delegate Demo 1 -----");
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fb3 = new Feedback(di.FeedbackToFile); Feedback fbChain = null;
fbChain = (Feedback)Delegate.Combine(fbChain, fb1);
fbChain = (Feedback)Delegate.Combine(fbChain, fb2);
fbChain = (Feedback)Delegate.Combine(fbChain, fb3);
Counter(, , fbChain); Console.WriteLine();
fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));
Counter(, , fbChain);
} private static void ChainDelegateDemo2(DelegateIntro di) {
Console.WriteLine("----- Chain Delegate Demo 2 -----");
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fb3 = new Feedback(di.FeedbackToFile); Feedback fbChain = null;
fbChain += fb1;
fbChain += fb2;
fbChain += fb3;
Counter(, , fbChain); Console.WriteLine();
fbChain -= new Feedback(FeedbackToMsgBox);
Counter(, , fbChain);
} private static void Counter(Int32 from, Int32 to, Feedback fb) {
for (Int32 val = from; val <= to; val++) {
// If any callbacks are specified, call them
if (fb != null)
fb(val);
}
} private static void FeedbackToConsole(Int32 value) {
Console.WriteLine("Item=" + value);
} private static void FeedbackToMsgBox(Int32 value) {
MessageBox.Show("Item=" + value);
} private void FeedbackToFile(Int32 value) {
StreamWriter sw = new StreamWriter("Status", true);
sw.WriteLine("Item=" + value);
sw.Close();
}
}
我们看到ChainDelegateDemo1里使用了Delegate.Combine这个静态方法来创建一个委托链,而ChainDelegateDemo2使用的是+=这个运算符的重载。
实际上CLR内部的情况正如ChainDelegateDemo1所示,调用了Delegate.Combine来创建委托链。+=号只是C#编译器提供的语法糖而已。
相似的,我们也可以使用Delegate.Remove或者-=来从委托链中移除一个委托。
4.委托和观察者模式。
首先看看观察者模式的定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。[GOF 《设计模式》]
重点在于:
当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知
所以这种模式中会有两个对象存在:观察者(订阅者),通知者(发布者)
观察者希望发布者通知他何时去更新,发布者希望能够增加或者减少发布者的数量并且通知观察者。简单的代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication4
{
//定义一个通知者类,当需要更新的时候通知观察者进行更新
class NotifyClass
{
public delegate void Update(NotifyClass nc);
public Update UpdateEvent;
public Int32 i_Update;
public void Notify()
{
if (UpdateEvent != null)
{
UpdateEvent(this);
}
}
}
//OB1类中只有一个方法监听通知类的通知事件
class Observer1
{
public void Ob1NotifiedUpdate(NotifyClass nc)
{
Console.WriteLine(nc.i_Update);
}
}
class Observer2
{
public void Ob2NotifiedUpdate(NotifyClass nc)
{
Console.WriteLine(nc.i_Update+" from ob2");
}
}
class Program
{
static void Main(string[] args)
{
NotifyClass a = new NotifyClass();
a.UpdateEvent += (new Observer1().Ob1NotifiedUpdate);
a.UpdateEvent += (new Observer2().Ob2NotifiedUpdate);
a.i_Update=100;
a.Notify();
Console.Read();
}
}
}
我们可以知道,观察者模式的情况其实是发布者通知观察者需要更新,然后观察者去更新。但是正如我之前说的,使用委托的实际情况是委托对象将方法包装起来,然后由委托对象去调用包装起来的方法。并不是由观察者去调用的。或者我们可以理解为真正监听发布者的不是观察者,而是通过观察者方法构建的委托对象。
所以我觉得下面的实现方式更加符合观察者模式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication4
{
//定义一个通知者类,当需要更新的时候通知观察者进行更新
class NotifyClass
{
public interface IUpdate
{
void Updated(NotifyClass nc);
}
public List<IUpdate> UpdateEvent=new List<IUpdate>();
public Int32 i_Update;
public void Notify()
{
if (UpdateEvent != null)
{
foreach (IUpdate iu in UpdateEvent)
{
iu.Updated(this);
}
}
}
public void AddListener(IUpdate iu)
{
UpdateEvent.Add(iu);
}
public void RemoveListener(IUpdate iu)
{
UpdateEvent.Remove(iu);
}
}
//OB1类中只有一个方法监听通知类的通知事件
class Observer1:NotifyClass.IUpdate
{public void Updated(NotifyClass nc)
{
Console.WriteLine(nc.i_Update);
}
}
class Observer2:NotifyClass.IUpdate
{
public void Updated(NotifyClass nc)
{
Console.WriteLine(nc.i_Update+" from ob2");
}
}
class Program
{
static void Main(string[] args)
{
NotifyClass a = new NotifyClass();
Observer1 ob1 = new Observer1();
a.AddListener(ob1);
a.i_Update = ;
a.Notify();
Console.Read();
}
}
}
CLR VIA C#委托的更多相关文章
- CLR读书笔记——委托
协变性和逆变性 协变性是指方法能返回从委托返回类型派生的一个类型. 逆变性是指获取的参数可以是委托参数类型的基类. 举个例子吧,看以下定义的委托,以及方法. delegate Object MyCal ...
- 读书笔记—CLR via C#委托和attribute
前言 这本书这几年零零散散读过两三遍了,作为经典书籍,应该重复读反复读,既然我现在开始写博了,我也准备把以前觉得经典的好书重读细读一遍,并且将笔记整理到博客中,好记性不如烂笔头,同时也在写的过程中也可 ...
- CLR之委托的揭秘(一)
初识委托: 在之前的学习中我们已经可以把对象,值,数组当作参数传递给方法,但是有没有可能把方法也当作参数传递给方法呢?有了这个想法于是就有了委托.方法当作一种参数去传递,但是方法有的 ...
- 《CLR.via.C#第三版》第二部分第12章节 泛型 读书笔记(六)
终于讲到泛型了.当初看到这个书名,最想看的就是作者对泛型,委托,反射这些概念的理解.很多人对泛型的理解停留在泛型集合上,刚开始我也是,随着项目越做越多,对待泛型的认识也越来越深刻. 泛型的概念:泛型是 ...
- [CLR via C#]12. 泛型
泛型(generic)是CLR和编程语言提供一种特殊机制,它支持另一种形式的代码重用,即"算法重用". 简单地说,开发人员先定义好一个算法,比如排序.搜索.交换等.但是定义算法的开 ...
- CLR类型设计之泛型(二)
在上一篇文章中,介绍了什么是泛型,以及泛型和非泛型的区别,这篇文章主要讲一些泛型的高级用法,泛型方法,泛型接口和泛型委托,协变和逆变泛型类型参数和约束性,泛型的高级用法在平时的业务中用的不多,多用于封 ...
- CLR via C#关于泛型(Generics )的摘录
泛型,是CLR和编程语言提供的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”. 简单的说,开发人员先定义好一个算法,比如排序.搜索.交换.比较或者转换等.但是,定义算法的开发人员并不设改算法 ...
- CLR via c#读书笔记八:泛型
1.定义泛型类型或方法时,为类型指定的任何变量(比如T)都称为类型参数.使用泛型类型或方法时指定的具体数据类型称为类型实参. 2.System.Collections.Concurrent命名空间提供 ...
- 重温CLR(八 ) 泛型
熟悉面向对象编程的开发人员都深谙面向对象的好处,其中一个好处是代码重用,它极大提高了开发效率.也就是说,可以派生出一个类,让他继承基类的所有能力.派生类只需要重写虚方法,或添加一些新方法,就可定制派生 ...
随机推荐
- Thrift 个人实战--Thrift RPC服务框架日志的优化
前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...
- HDU 1372 Knight Moves (bfs)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1372 Knight Moves Time Limit: 2000/1000 MS (Java/Othe ...
- ajax data数据里面传一个json到后台的写法
$.ajax({ url:url+"/crm/contact", type:'PUT', ...
- C++ Primer : : 第十四章 : 重载运算符与类型转换之类型转换运算符和重载匹配
类型转换运算符 class SmallInt { public: SmallInt(int i = 0) : val(i) { if (i < 0 || i > 255) throw st ...
- NOIP2015 跳石头
一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N块岩石(不含起点和终点的岩石). ...
- Mysql外键约束设置使用方法
如果表A的主关键字是表B中的字段,则该字段称为表B的外键,表A称为主表,表B称为从表.外键是用来实现参照完整性的,不同的外键约束方式将可以使两张表紧密的结合起来,特别是修改或者删除的级联操作将使得日常 ...
- 032. asp.netWeb用户控件之一初识用户控件并为其自定义属性
Web用户控件的优点: 可以将常用的内容或者控件以及控件的运行程序逻辑, 设计为用户控件, 以后便可以在多个页面中重复使用该用户控件, 从而省去许多重复性的工作. 如网页上的导航栏, 几乎每个页面都需 ...
- ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室 实战系列(不断更新中)
项目简介 利用ASP.NET SignalR技术与Layim前端im框架实现的一个简单的web聊天室,包括单聊,群聊,加好友,加群,好友搜索,管理,群组管理,好友权限设置等功能.涉及技术: Elast ...
- 【mysql】一维数据TopN的趋势图
创建数据表语句 数据表数据 对上述数据进行TopN排名 select severity,sum(count) as sum from widgt_23 where insertTstamp>=' ...
- TIOBE Index for December 2015(转载)
There is hardly any doubt about it, Java will become TIOBE's programming language of the year 2015. ...