一. 泛型委托

  所谓的泛型委托,即自定义委托的参数可以用泛型约束,同时内置委托Func和Action本身就是泛型委托。

  将上一个章节中的Calculator类中的方法用自定义泛型委托重新实现一下。

  public class Calculator2
{
//传统解决方案一:在该类中声明多个方法,分别是加倍、平方、立方的方法 //传统解决方案二:在该类中声明一个万能方法,通过传递不同的参数类型来区分是执行加倍还是平方或者立方操作 //解决方案三:声明一个万能方法,传递一个委托进来,相当于传递了一个业务逻辑进行,在该方法里只需要执行即可
/// <summary>
/// 万能方法
/// </summary>
/// <param name="arrs">int类型的数组 </param>
/// <param name="mydel">自定义委托</param>
public delegate T myDel<T>(T t);
public static void MySpecMethord<T>(T[] arrs, myDel<T> myDel)
{
for (int i = ; i < arrs.Length; i++)
{
arrs[i] = myDel(arrs[i]);
//arrs[i] = mydel.Invoke(arrs[i]); //等价于上面那句
Console.WriteLine(arrs[i]);
}
} }

二. 内置委托

  .Net FrameWork提供两个支持泛型的内置委托,分别是Action和Func,结合lambda表达式,可以提高开发效率

  二者的区别:

  1.Action只能委托无返回值的方法,支持16个重载(in代表输入参数,该重载没有返回值)

  分别是:

    * public delegate void Action<in T>(T obj);

    * public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);

    * ......

    * public delegate void Action<in T1, in T2,......,in T16>(T1 arg1, T2 arg2,......,T16 arg16);

    *

  2.Func必须委托有返回值的方法,支持17个重载(注意括号里最后一个代表返回值,in代表输入参数,out代表返回值)

  分别是:

    * public delegate TResult Func<out TResult>();

    * public delegate TResult Func<in T, out TResult>(T arg);

    * public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);

    * ......

    * public delegate TResult Func<in T1, in T2,.......in T16 out TResult>(T1 arg1, T2 arg2,......T16 arg16);

    *

  总结:除了ref参数和out参数,内置委托基本上能适用于任何泛型委托的场景,非常好用

    3. 内置委托和自定义委托的区别:

  自定义委托需要先声明一下,让系统认识这个自定义委托,然后才能实例化赋值方法;而内置委托系统本事就存在,所有不需要事先声明,直接实例化赋值方法即可

三. 委托的其它性质

  静态方法和实例方法对于委托的区别,对于静态方法,Target属性为null,所以效率比实例属性更高

  public class OtherCharacters
{
public delegate void mySpecDelegate();
/// <summary>
/// 1.测试普通实例方法和静态方法在委托中的区别
/// </summary>
public static void Test1()
{
MR mr=new MR();
//实例方法
mySpecDelegate a = mr.f1;
Console.WriteLine(a.Target==mr); //true
//静态方法
mySpecDelegate b = MR.f2;
Console.WriteLine(b.Target==null); //true
} } public class MR
{
/// <summary>
/// 普通方法
/// </summary>
public void f1()
{
}
//静态方法
public static void f2()
{ }
}

四. 事件

 1. 事件介绍

  * 定义:声明一个委托实例,然后在该实例的前面加上event关键字,就形成事件了

  * 事件的用途:实现广播和订阅的场景

  * 1.广播者:包括1个事件字段,独享执行委托的方法

  * 2.订阅者:通过调用 += 和 -= 来决定何时开始或停止订阅

  * 总结:事件是描述这种场景模式的一个词,事件是委托的一个子集,为了满足“广播/订阅”模式的需求而生

  * 事件和委托的区别:

  * 1. 委托是一种类型,而事件是委托的一个实例,然后在该实例前加上一个关键字

  * 2. 事件有一系列规则和约束用以保证程序的安全可控,事件只有 += 和 -= 操作,这样订阅者只能有订阅或取消订阅操作,没有权限执行其它操作

  * 3. 如果是委托,那么订阅者就可以使用 = 来对委托对象重新赋值(其它订阅者全部被取消订阅),甚至将其设置为null,甚至订阅者还可以直接调用委托,这些都是很危险的操作,广播者就失去了独享控制权

  * 4. 事件保证了程序的安全性和健壮性

 2. 下面代码就事件和委托进行比较

 public class MyEvent
{
//下面的案例用委托和事件实现相同的功能
public Action myDelegate;
/// <summary>
/// 触发委托执行的方法
/// </summary>
public void realizeDelegate()
{
if (myDelegate != null)
{
myDelegate.Invoke();
}
}
public event Action myEvent;
/// <summary>
/// 触发事件执行的方法
/// </summary>
public void realizeEvent()
{
if (myEvent != null)
{
myEvent.Invoke();
}
} #region 供委托和事件测试调用的方法 public static void T1()
{
Console.WriteLine("方法一");
} public static void T2()
{
Console.WriteLine("方法二");
} public static void T3()
{
Console.WriteLine("方法三");
} #endregion }

 3. 调用时候的区别:

 委托中的订阅者可以直接Invoke()来调用委托,而事件中的订阅者不能直接Invoke()调用委托,只能通过广播者中的方法来实现调用委托,从而保证广播者独享控制权。

  {
Console.WriteLine("--------------------------七. 事件------------------------------------");
MyEvent m1 = new MyEvent();
//1. 委托实现
Console.WriteLine("--------------------------1. 委托实现------------------------------------");
//订阅者进行订阅
m1.myDelegate += MyEvent.T1;
m1.myDelegate += MyEvent.T2;
m1.myDelegate += MyEvent.T3;
m1.myDelegate.Invoke(); //委托中的订阅者可以直接调用委托
m1.myDelegate -= MyEvent.T2;
m1.realizeDelegate();
//2. 事件实现
Console.WriteLine("--------------------------2. 事件实现------------------------------------");
m1.myEvent += MyEvent.T1;
m1.myEvent += MyEvent.T2;
m1.myEvent += MyEvent.T3;
// m1.myEvent.Invoke(); //事件中的订阅者不能直接调用委托
m1.realizeEvent(); //只能通过发布者中方法来实现委托,保证发布者独享控制权
m1.myEvent -= MyEvent.T2;
m1.realizeEvent(); }

  结果:

第十节:委托和事件(2)(泛型委托、Func和Action、事件及与委托的比较)的更多相关文章

  1. 第一百二十节,JavaScript事件对象

    JavaScript事件对象 学习要点: 1.事件对象 2.鼠标事件 3.键盘事件 4.W3C与IE JavaScript事件的一个重要方面是它们拥有一些相对一致的特点,可以给你的开发提供更多的强大功 ...

  2. C# 关于委托和事件的妙文:通过一个例子详细介绍委托和事件的作用;Observer模式简介

    委托和事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见 ...

  3. 按自己的想法去理解事件和泛型(C#)

    上一篇那些年困扰我们的委托(C#)讲了委托,这一篇自然就轮到事件了. 不喜欢官方的表达方式,喜欢按照自己的想法去理解一些抽象的东西. 事件 考虑到委托使用的一些缺陷,就有了事件.委托是不安全的,打个比 ...

  4. 第三百五十节,Python分布式爬虫打造搜索引擎Scrapy精讲—selenium模块是一个python操作浏览器软件的一个模块,可以实现js动态网页请求

    第三百五十节,Python分布式爬虫打造搜索引擎Scrapy精讲—selenium模块是一个python操作浏览器软件的一个模块,可以实现js动态网页请求 selenium模块 selenium模块为 ...

  5. centos LAMP第二部分apache配置 下载discuz!配置第一个虚拟主机 安装Discuz! 用户认证 配置域名跳转 配置apache的访问日志 配置静态文件缓存 配置防盗链 访问控制 apache rewrite 配置开机启动apache tcpdump 第二十节课

    centos    LAMP第二部分apache配置  下载discuz!配置第一个虚拟主机 安装Discuz! 用户认证 配置域名跳转  配置apache的访问日志  配置静态文件缓存  配置防盗链 ...

  6. centos shell编程6一些工作中实践脚本 nagios监控脚本 自定义zabbix脚本 mysql备份脚本 zabbix错误日志 直接送给bc做计算 gzip innobackupex/Xtrabackup 第四十节课

    centos   shell编程6一些工作中实践脚本   nagios监控脚本 自定义zabbix脚本 mysql备份脚本 zabbix错误日志  直接送给bc做计算  gzip  innobacku ...

  7. C#编程语言之委托与事件(一)—— C/C++函数指针和C#委托初步

    相信正在学习C#的人都有学习过C或C++的经验,本文要讲的第一个要点是C#中的委托(delegate,有些资料也叫代表).什么是委托,很多人都能自然而然地想到C/C++中的函数指针,事实上很多书和资料 ...

  8. 第十节:详细讲解一下Java多线程,随机文件

    前言 大家好,给大家带来第十节:详细讲解一下Java多线程,随机文件的概述,希望你们喜欢 多线程的概念 线程的生命周期 多线程程序的设计 多线程的概念 多线程的概念:程序是静态的,进程是动态的.多进程 ...

  9. 第三百八十节,Django+Xadmin打造上线标准的在线教育平台—将所有app下的models数据库表注册到xadmin后台管理

    第三百八十节,Django+Xadmin打造上线标准的在线教育平台—将所有app下的models数据库表注册到xadmin后台管理 将一个app下的models数据库表注册到xadmin后台管理 重点 ...

随机推荐

  1. GDB调试指南-启动调试

    前言 GDB(GNU Debugger)是UNIX及UNIX-like下的强大调试工具,可以调试ada, c, c++, asm, minimal, d, fortran, objective-c, ...

  2. 滑动窗口最大值的golang实现

    给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口 k 内的数字.滑动窗口每次只向右移动一位. 返回滑动窗口最大值 输入: nums = [, ...

  3. centos7源码包安装Mongodb,并设置开机自启动

    1.下载源码包 curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.2.12.tgz 2.解压 放到 /usr/local/ ...

  4. Zabbix 3.4.7调整监控阈值以及告警级别

    1.找到需要监控的主机:右上角进行搜索 我们要更改sepm02p的阈值和级别: 进行更改级别:先点击Triggers , 选中要更改的监控项,例如我要更改CPU,点击以下红色标出的,千万不要选择Tem ...

  5. CentOS 7 软件安装简记

    Install SW Record ================= $ sudo yum install vim-X11.x86_64 $ sudo yum install clang.x86_6 ...

  6. Kafka 详解(一)------简介

    在前面几篇博客我们介绍过一种消息中间件——RabbitMQ,本篇博客我们介绍另外一个消息中间件——Kafka,Kafka是由LinkedIn开发的,使用Scala编写,是一种分布式,基于发布/订阅的消 ...

  7. Elastic Stack-Elasticsearch使用介绍(一)

    一.前言     Elasticsearch对外提供RESTful API,下面的演示我们主要使用Postman,进行一系列的Demo演示,这款工具方便各位前端大大或者对接口调试的神器: 安装过于简单 ...

  8. 轻量级ORM框架 Bankinate

    [前言] 前面讲过ORM的前世今生,对ORM框架不了解的朋友可以参考博文:https://www.cnblogs.com/7tiny/p/9551754.html 今天,我们主要通过设计一款轻量级的O ...

  9. 在Asp.Net Core中使用DI的方式使用Hangfire构建后台执行脚本

    最近项目中需要用到后台Job,原有在Windows中我们会使用命令行程序结合计划任务或者直接生成Windows Service,现在.Net Core跨平台了,虽然Linux下也有计划任务,但跟原有方 ...

  10. Leetcode 226. Invert Binary Tree(easy)

    Invert a binary tree. 4 / \ 2 7 / \ / \ 1 3 6 9 to 4 / \ 7 2 / \ / \ 9 6 3 1 Trivia:This problem was ...