一. 泛型委托

  所谓的泛型委托,即自定义委托的参数可以用泛型约束,同时内置委托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. 进程命令(tasklist)

    TaskList命令: // 描述: 显示本地或远程计算机上正在运行的进程列表信息. // 语法: tasklist [/s <computer> [ /u [<domain> ...

  2. Django REST framework基础:版本控制

    DRF的版本控制 为什么需要版本控制 API 版本控制允许我们在不同的客户端之间更改行为(同一个接口的不同版本会返回不同的数据). DRF提供了许多不同的版本控制方案. 可能会有一些客户端因为某些原因 ...

  3. HBase源码实战:CreateRandomStoreFile

    /* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agre ...

  4. supervisord支持扩展(xml RPC API & Third Party Applications and Libraries)

    XML-RPC API Documentation http://www.supervisord.org/api.html Third Party Applications and Libraries ...

  5. Taro项目遇到的问题

    1. https://taro-ui.aotu.io/#/docs/questions 请在Taro项目根目录找到 config/index.js 文件中的h5项,添加如下: h5: { ... es ...

  6. day 13 迭代器、可迭代对象、迭代器对象、生成器、生成器对象、枚举对象

    迭代器大概念 # 迭代器:循环反馈的容器(集合类型)# -- 不同于索引取值,但也可以循环的从容器对象中从前往后逐个返回内部的值​# 优点:不依赖索引,完成取值# 缺点:不能计算长度,不能指定位取值( ...

  7. Mac系统下Mysql存储数据报错 ER_TRUNCATED_WRONG_VALUE_FOR_FIELD: Incorrect string value

    比如如下mysql操作插入数据: const mysql = require('mysql'); /* createConnection方法创建一个表示与Mysql数据库服务器之间连接的 Connec ...

  8. Python脱产8期 Day13 2019/4/28

    一 函数的嵌套定义 1在一个函数的内部定义另一个函数. 2.为什么有函数的嵌套定义: # 1)函数fn2想直接使用fn1函数的局部变量,可以讲fn2直接定义到fn1的内部,这样fn2就可以直接访问fn ...

  9. git 命令积累

    git status # 查看仓库的状态 git add . # 监控工作区的状态树,使用它会把工作时的所有变化提交到暂存区,包括文件内容修改(modified)以及新文件(new),但不包括被删除的 ...

  10. keepalived--小白博客

    一.HA集群中的相关术语 1.节点(node) 运行HA进程的一个独立主机,称为节点,节点是HA的核心组成部分,每个节点上运行着操作系统和高可用软件服务,在高可用集群中,节点有主次之分,分别称之为主节 ...