在前面lambda章节中稍微提了一下委托,今天这章就让我们来深究一下委托。

委托的本质是一种类,他是继承MulticastDelegate类的。

而声明委托的关键字的delegate,如:public delegate void NoReturnNoParaOutClass();

但是刚才也讲了委托一种类,那按照类的声明,我们应该可以这样声明一个委托。

public class  NoReturnNoParaOutClass: System.MulticastDelegate
{ }

只不过由于这种类比较特殊,因为它由于框架限定,这种做法在.net框架中是不被允许的,所以我们只能通过delegate关键字来声明委托。

下面讲讲委托应该怎么用。

用委托分为三个步骤:

1)声明委托

2)委托实例化

3)委托的调用

public delegate void NoReturnNoPara();//1声明委托
NoReturnNoPara method = new NoReturnNoPara(this.DoNothing);//2 委托的实例化
method.Invoke();//3 委托的调用 private void DoNothing()
{
Console.WriteLine("This is DoNothing");
}

在前面的章节也讲过,实例化委托时必须保证委托的签名和方法的签名保持一致。

再说个例子来阐述委托的用法。

假设有一个这样的需求,有一个汽车工厂,生产一款汽车。按照一般的做法应该是这样的

 public void BuildCar()
{
Console.WriteLine("造一个发动机"); Console.WriteLine("造一个外壳"); Console.WriteLine("造一个底盘"); Console.WriteLine("造四个轮子"); Console.WriteLine("组装成一辆车"); Console.WriteLine("造好了一辆车。。");
}

但是由于社会在进步,车子的性能也在提升,车子的发动机也需要跟新换代,在以前只有自然吸气,现在需要增加 涡轮增压和电动,按照一般的改法的话。

  public void BuildCar(EngineType engineType)
{
if (engineType == EngineType.NaturalInspiration)
{
Console.WriteLine("造一个自然吸气发动机");
}
else if (engineType == EngineType.Turbo)
{
Console.WriteLine("造一个涡轮增压发动机");
}
else if (engineType == EngineType.Electric)
{
Console.WriteLine("造一个电池发动机");
} Console.WriteLine("造一个外壳"); Console.WriteLine("造一个底盘"); Console.WriteLine("造四个轮子"); Console.WriteLine("组装成一辆车"); Console.WriteLine("造好了一辆GTR。。");
} public enum EngineType
{
NaturalInspiration = 0,
Turbo = 1,
Electric = 2 }

这种做法通过上端程序调用时传递一个参数来判断生产哪一种发动机。但是这样做对工厂的要求太大,万一以后出现了太阳能的岂不是对工厂的整体生产线都要进行修改,这样做的成本太大,不切合实际,而且现在的工厂一般都是只做组装工作,生产的任务都是外包出去。那么我们程序应该怎么改呢,毕竟程序源自于生活。要符合实际情况才行。

这个时候就需要使用委托了

我们把生产发动机都给剥离出来,在生产厂家只需要组装就行。

       public void BuildEngineNaturalInspiration()
{
Console.WriteLine("造一个自然吸气发动机");
}
public void BuildEngineTurbo()
{
Console.WriteLine("造一个涡轮增压发动机");
}
public void BuildEngineElectric()
{
Console.WriteLine("造一个电池发动机");
}

那后再类中声明一个委托,并修改BuildCar方法。

 public void BuildCar(BuildEngineDelegate method)
{
method.Invoke(); Console.WriteLine("造一个外壳"); Console.WriteLine("造一个底盘"); Console.WriteLine("造四个轮子"); Console.WriteLine("组装成一辆车"); Console.WriteLine("造好了一辆GTR。。");
} public delegate void BuildEngineDelegate();

在上端调用时直接传递一个方法,内部调用一下完成组装,这样做生产厂家就不必考虑应该怎么做了,你调用的时候直接给我,而我这里就完成一个组装工作。

    CarFactory.BuildEngineDelegate method = new CarFactory.BuildEngineDelegate
carFactory.BuildEngineNaturalInspiration);
carFactory.BuildCar(method);

这样做厂家就对发动机怎么做的依赖性不那么强了。

再来讲个黑科技,有许多人写程序时不愿意写异常处理。在这里可以直接写一个异步处理,通过委托可以绑定在任何方法上。

        /// <summary>
/// 通用的异常处理
/// </summary>
/// <param name="act">对应任何的逻辑</param>
public static void SafeInvoke(Action act)
{
try
{
act.Invoke();
}
catch (Exception ex)//按异常类型区分处理
{
Console.WriteLine(ex.Message);
}
}

调用时只需要这样做就可以一步完成异步处理功能。

        CarFactory.SafeInvoke(() => carFactory.BuildCar(method));

最后在讲讲多播委托,提到多播委托就不得不提提设计模式中的观察者模式。

我们假设有一只猫叫了一声,然后狗叫,老鼠跑,小孩就哭了,妈妈也醒了。爸爸就大叫,邻居也被吵醒,小偷也赶快溜了。

就因为猫的叫,导致一系列的触发动作

    public class Cat
{
public void Miao()
{
Console.WriteLine("{0} Miao", this.GetType().Name);
new Dog().Wang();
new Mouse().Run(); new Baby().Cry();
new Mother().Wispher();
new Brother().Turn();
new Father().Roar();
new Neighbor().Awake();
new Stealer().Hide(); }
}

为了篇幅,其他类就不写上来了,都是简单的一些方法。。

假如猫叫一声,不是狗先叫,而是老鼠先跑,那岂不又要修改猫这个类,再说老鼠跑不跑管猫什么事,我叫我叫的,你爱干啥干啥,管我什么事,

但是这样的程序设计就必须修改猫这个类的方法。这个时候我们就要思考了,可不可把方法抽离出来,别那么依赖猫。其实用委托就可以实现这个功能。

声明一个委托,并在猫类中调用委托。

        public Action MiaoAction;

public event Action MiaoActionEvent;
                 public void MiaoEvent()
                  {
                     Console.WriteLine("{0} MiaoActionEvent", this.GetType().Name);
                     if (MiaoActionEvent != null)
                     MiaoActionEvent.Invoke();
  
                  }

这个上端调用只需要这样做。

                    Console.WriteLine("************cat.MiaoEvent();***********");
cat.MiaoActionEvent += new Dog().Wang;//订阅
cat.MiaoActionEvent += new Mouse().Run;
cat.MiaoActionEvent += new Baby().Cry;
cat.MiaoActionEvent += new Mother().Wispher;
cat.MiaoActionEvent += new Brother().Turn;
cat.MiaoActionEvent += new Father().Roar;
cat.MiaoActionEvent += new Neighbor().Awake;
cat.MiaoActionEvent += new Stealer().Hide;
cat.MiaoEvent();

  在上面中提到了Event关键字,它就是事件,那么委托和事件是怎样的关系呢。

委托是一种类型,而事件是委托的一个实例

其实事件控制了实例的使用权限,更加安全。

事件不能再其他类中调用,只能在声明事件的类中调用,这就保证了事件的安全。

在观察者模式中。分为发布者,订户,和订阅者。

在本例中,猫就是那个发布者,而狗、小孩就是订户,最后调用时,上端是订阅者。而事件的发布只能声明在引起这一系列动作类中。

那么使用委托的意义是什么呢,使用委托主要是为了解耦,是程序之间的依赖关系不是那么强。还有多线程,这个以后再讲。

  

 

Delegate(委托)的更多相关文章

  1. 快速理解C#高级概念(一) Delegate委托

    做.NET开发很久,最近重新温习<C#高级编程>一书.发现很多曾经似懂非懂的问题,其实也是能够慢慢钻研慢慢理解的. 所以,打算开写<C#高级编程系列>博文.其中会借鉴<C ...

  2. WPF Delegate委托整理

    那啥,是从这里整理出来的,感谢Rising_Sun,整理的过于简单,看不明白的戳这里 using System; using System.Collections.Generic; using Sys ...

  3. 关于js模拟c#的Delegate(委托)实现

    这是我的第一篇博文,想来讲一讲js的函数.我的标题是js模拟c#的Delegate. 一.什么是Delegate(委托) 在jquery中有delegate函数,作用是将某个dom元素的标签的事件委托 ...

  4. 使用 EPPlus 封装的 excel 表格导入功能 (二) delegate 委托 --永远滴神

    使用 EPPlus 封装的 excel 表格导入功能 (二) delegate 委托 --永远滴神 前言 接上一篇 使用 EPPlus 封装的 excel 表格导入功能 (一) 前一篇的是大概能用但是 ...

  5. 【UE4 C++ 基础知识】<8> Delegate 委托

    概念 定义 UE4中的delegate(委托)常用于解耦不同对象之间的关联:委托的触发者不与监听者有直接关联,两者通过委托对象间接地建立联系. 监听者通过将响应函数绑定到委托上,使得委托触发时立即收到 ...

  6. C#delegate委托

    类似函数,却没有语句体. using System; using System.Collections.Generic; using System.Linq; using System.Text; u ...

  7. C# EventHandler and Delegate(委托的使用)

    委托的声明 public delegate void MyDelegate(string str); 注 1.委托的定义和方法的定义类似,只是在前面加了一个delegate,但委托不是方法,它是一种特 ...

  8. C# 匿名方法 委托 Action委托 Delegate委托

    原文地址:https://msdn.microsoft.com/zh-cn/library/bb882516.aspx 匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用. 可以使用匿 ...

  9. 转载: jQuery事件委托( bind() \ live() \ delegate()) [委托 和 绑定的故事]

    转载:http://blog.csdn.net/zc2087/article/details/7287429 随着DOM结构的复杂化和Ajax等动态脚本技术的运用,事件委托自然浮出了水面.jQuery ...

  10. 转:C# Delegate委托 1

    Delegate中文翻译为“委托”.MSDN中对Delegate的解释如下: C#中的委托类似于C或C++中的函数指针.使用委托使程序员可以将方法引用封装在委托对象内.然后可以将该委托对象传递给可调用 ...

随机推荐

  1. jar包和war包

    Jar (Java archive), 是将实现了某功能的所有类及辅助资源用ZIP压缩形式打包而成的一个文件, 便于代码的管理和重复使用.当使用别人提供的jar时,只需要在classpath环境变量中 ...

  2. hdu 1711---KMP

    题目链接 Problem Description Given two sequences of numbers : a[1], a[2], ...... , a[N], and b[1], b[2], ...

  3. 4.docker学习之镜像

    镜像 我们知道,我们想在Windows操作系统上跑Linux,需要安装一个虚拟机程序,然后下载一个Linux镜像,在该虚拟机程序中创建一个虚拟机,并使用该镜像安装对应的Linux操作系统,安装好之后, ...

  4. 深入理解Java常用类-----时间日期

    除了String这个类在日常的项目中比较常用之外,有关时间和日期的操作也是经常遇到的,本篇就讲详细介绍下Java API中对时间和日期的支持.其实在Java 8之前时间日期的API并不是很好用,以至于 ...

  5. YII缓存依赖的应用

    YII缓存依赖的应用 缓存 缓存依赖 Yii 缓存是提升Web应用性能的简便有效的方式.当我们在加载网页需要过多的时间,比如说查询时间过久,抑或是调用接口占用过多I/O,建立缓存是一个行之有效的方法, ...

  6. 【JAVAWEB学习笔记】网上商城实战5:后台的功能模块

    今日任务 完成后台的功能模块 1.1      网上商城的后台功能的实现: 1.1.1    后台的功能的需求: 1.1.1.1  分类管理: [查询所有分类] * 在左侧菜单页面中点击分类管理: * ...

  7. CentOS7安装PostgreSQL9.4

    这次选择的数据库安装的是run 文件,更容易掌握.这次数据库全是默认安装,如果有需求的可以自行修改一下的. 这是我的第一篇博客,各位观众老爷,如果觉得哪里有什么不好的,可以留言一起探讨,探讨.有什么问 ...

  8. 用java实现简单快速的webservice客户端/数据采集器(支持soap1.1和soap1.2标准,支持utf-8编码)

    前言: 用了cxf,axis等各种wbeservice实现库,简单试用了一下动态调用的方式,很不满意,完全无法满足业务的需要,所以自己实现了一个webservice采集客户端,方便动态调用外部webs ...

  9. 使用类似于中介者模式实现不同VC之间的跳转

    在2013年的时候,我们就已经实现了类似于http地址进行页面跳转, 那个时候,主要是用继承ViewController和给 UIViewController和UINavigationControll ...

  10. Cookie的作用以及封装的方法

    Cookie相当于本地储存(local Storage),也是一种储存信息的方式. 它通过 document.cookie ='name=value' //name name值 value value ...