委托的使用与原理简析

一.委托声明与本质

1.声明委托

public delegate void SayHelloDelegate(string who);

2.使用ILSpy反编译后,看其本质

public class auto ansi sealed SayHelloDelegate: MulticastDelegate
  • 编译器自动生成了一个委托类,继承自MulticastDelegate

  • 委托被标识为class,说明委托是一种数据类型:

    委托类即可嵌套在一个类型中定义,也可以在全局范围中定义,就是说由于委托是类,所以凡是能够定义类的地方,都能定义委托;当然也可以声明委托类的变量。

  • 委托被标识味sealed,说明是封闭类,不可以被继承

二.创建委托变量与本质

1.既然委托是类,并且不是静态类,想要使用,就必须new

//委托声明
public delegate void SayHelloDelegate(string who);

static void Main(string[] args)
{
    //创建委托变量(使用new关键字)
    SayHelloDelegate sayDel1 = new SayHelloDelegate(SayHelloToAmerican);
    //创建委托变量(不使用new关键字)
    SayHelloDelegate sayDel2 = SayHelloToAmerican;
}

//类的静态方法
static void SayHelloToAmerican(string who)
{
    Console.WriteLine("hello:" + who);
}

2.反编译看两种创建变量的方式,其本质是一样的

private static void Main(string[] args)
{
    Program.SayHelloDelegate sayDel1 = new Program.SayHelloDelegate(Program.SayHelloToAmerican);
    Program.SayHelloDelegate sayDel2 = new Program.SayHelloDelegate(Program.SayHelloToAmerican);
    Console.ReadLine();
}

编译器都会给搞成new,所以不带new的变量创建方式,是语法糖。

三.调用委托变量与本质

1.给委托变量加上()就相当于调用了

static void Main(string[] args)
{
    //创建委托变量(使用new关键字)
    SayHelloDelegate sayDel = new SayHelloDelegate(SayHelloToAmerican);

    //委托变量调用
    sayDel("jack");
}

2.反编译看其本质是调用了Invoke方法
所以我们自己也可以直接调用这个方法,委托变量调用的这两种方法,本质是一样的,编译器都会调用Invoke。简写方式也是语法糖。

sayDel("jack");
sayDel.Invoke("jack");

3.委托变量的调用本质上通过反射对方法的调用
这是委托的构造函数,有两个参数

public SayHelloDelegate(object target, string method)
{
}

委托类同时提供了两个只读属性TargetMethod供使用,是将委托变量指向的对象方法进行了包装,如果方法是静态方法,则Target为null,否则就指向对象的引用。Method属性返回一个System.Reflection.MethodInfo对象的引用。在我们调用Invoke方法时,其实是执行了委托变量指向的方法,只不过有一个内部包装和调用的机制。

四.委托的好处

1.逻辑分离、解除耦合
业务逻辑未来可能会变化,不能固定,分离处理;只要把委托给我,让我调用就可以了。
2.对修改封闭、对扩展开放
未来可以给我传任何一个代理,这就是扩展。
而我不需要修改任何代码,这就是封闭。
我省事,你随意。我好你也好。

五.委托的异步调用

反编译看到委托还有两个方法:

public IAsyncResult BeginInvoke(string who,   AsyncCallback callback, object @object)
{
}

public void EndInvoke(IAsyncResult result)
{
}

1.异步调用的本质和适合场景
这是异步调用方式,本质上是建立了一个线程,是简化的线程调用方法。

比较适合在后台运行比较耗费时间的简单任务,要求任务之间是独立的、建议任务中不有要直接访问可视化控件的逻辑
如果后台任务必须按照特定顺序执行,或者需要访问共享资源,异步编程不太适合,直接用多线程开发技术。

2.BeginInvoke跟Invoke的区别
调用Invoke,在Invoke的方法返回前,这个线程会阻塞;调用BeginInvoke,在BeginInvoke的方法返回前,这个线程不会阻塞!

六.多播委托与泛型委托

1.泛型委托变量指向多个方法并调用
委托可以声明为泛型的,一个委托变量可以指向多个方法。

private delegate string AddDelegate<T>(T i, T j);

private string MyAdd(int i, int j)
{
    Console.WriteLine(i + j + "");

    return i + j + "";
}

private void button2_Click(object sender, EventArgs e)
{
    AddDelegate<int> add = MyAdd;
    add += MyAdd;
    add += MyAdd;

    foreach (AddDelegate<int> item in add.GetInvocationList())
    {
        item(3, 4);
    }
}

add委托变量指向了一个委托方法链,如果使用add()直接调用,委托方法链中的每个方法都会调用,但是返回值只能是最后一个方法。
2.反编译看起本质

add = (AddDelegate<int>)Delegate.Combine(add, new AddDelegate<int>(this.MyAdd));
add = (AddDelegate<int>)Delegate.Combine(add, new AddDelegate<int>(this.MyAdd));

调用了基类Delegate的Combine方法加入了方法链。

七.委托与匿名方法

1.使用匿名方法简化代码
如果委托指向的方法只是临时用一下,明确声明一个方法就显得啰嗦了,这个时候可以使用匿名方法

private delegate void SayHelloHandler(string name);

private void SayHelloToSomeone(string name, SayHelloHandler sayHandler)
{
    sayHandler(name);
}

private void SayHelloTest()
{
    //标准匿名方法
    SayHelloHandler sayAmerican = new SayHelloHandler(delegate (string name) { Console.WriteLine("你好:" + name); });
    SayHelloToSomeone("jack", sayAmerican);

    //省略new,编译器会自动加上new
    SayHelloHandler sayAmerican1 = delegate (string name) { Console.WriteLine("你好:" + name); };
    SayHelloToSomeone("jack", sayAmerican);

    //可以简化为lambda表达式
    SayHelloHandler sayChinese = name => Console.WriteLine("你好:" + name);
    SayHelloToSomeone("李老师", sayChinese);
}

private void button3_Click(object sender, EventArgs e)
{
    SayHelloTest();
}

2.lambda的本质是匿名方法
反编译看,lambda表达式本质上是匿名方法,编译器自动生成了这个方法。

private sealed class <>c
{
    internal void <SayHelloTest>b__9_0(string name)
    {
        Console.WriteLine("hello:" + name);
    }

    internal void <SayHelloTest>b__9_1(string name)
    {
        Console.WriteLine("你好:" + name);
    }
}

3.委托的严格限制
方法的参数和返回值必须和委托签名保持一致。可以省略lambda的参数类型,编译器将自动推断。

//可以简化为lambda表达式
SayHelloHandler sayChinese = name => Console.WriteLine("你好:" + name);
时间: 2024-08-22 22:34:28

委托的使用与原理简析的相关文章

PHP的错误报错级别设置原理简析

原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices including coding standards.) ; E_ALL & ~E_NOTICE (Show all errors, except for notices) ; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for

Java Annotation 及几个常用开源项目注解原理简析

文简单介绍下 Annotation 示例.概念及作用.分类.自定义.解析,并对几个 Android 开源库 Annotation 原理进行简析. PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示例 Override Annotation Java 1 2 @Override public void onCreate(Bundle savedIns

腾讯Android自动化测试实战3.2 Robotium原理简析

3.2 Robotium原理简析 如前文所述,一个基本的自动化测试用例主要分为获取控件.控件操作.断言三个步骤,而在实际编写测试用例的过程中,我们常常会遇到各种各样的问题,比如: 在这样的UI结构下该如何获取控件? 为何报这样或那样的错? 明明滑动了为何没有效果? 因为不同的项目有其自身的独特性与复杂性,没有任何书籍可以解决实际过程中遇到的所有问题,甚至即使求助Google搜索也可能得不到自己想要的答案.因此,对于任何一门技术而言都很有必要知其然并知其所以然,只有了解了其原理实现,才能更高效地运

javascript事件委托的用法及其好处简析_javascript技巧

本文为大家简单介绍了javascript事件委托的用法及其好处,供大家参考,具体内容如下 事件委托:利用冒泡的原理,把事件加到父级上,触发执行效果, 好处:提高性能,新添加的元素还会有之前的事件. event对象:事件源,不管在哪个事件中,只要你操作的那个元素就是事件源 获取事件源:IE:window.event.srcElement  标准下:event.target  target.nodeName来判断是哪个标签 代码应用如下: <!DOCTYPE html PUBLIC "-//W

Android热补丁技术—dexposed原理简析(手机淘宝采用方案)

上篇文章<Android无线开发的几种常用技术>我们介绍了几种android移动应用开发中的常用技术,其中的热补丁正在被越来越多的开发团队所使用,它涉及到dalvik虚拟机和android的一些核心技术,现在就来介绍下它的一些原理. 本篇先介绍dexposed方案:https://github.com/alibaba/dexposed,它是手机淘宝团队使用的热补丁方案,后来开源到github上,取的名字dexposed表明了自己是基于大名鼎鼎的xposed hook方案,有饮水思源.回馈开源项

cpu工作原理简析

在了解CPU工作原理之前,我们先简单谈谈CPU是如何生产出来的.CPU是在特别纯净的硅材料上制造的.一个CPU芯片包含上百万个精巧的晶体管.人们在一块指甲盖大小的硅片上,用化学的方法蚀刻或光刻出晶体管.因此,从这个意义上说,CPU正是由晶体管组合而成的.简单而言,晶体管就是微型电子开关,它们是构建CPU的基石,你可以把一个晶体管当作一个电灯开关,它们有个操作位,分别代表两种状态:ON(开)和OFF(关).这一开一关就相当于晶体管的连通与断开,而这两种状态正好与二进制中的基础状态"0"和

ARP攻击原理简析及防御措施

0x1  简介 网络欺骗攻击作为一种非常专业化的攻击手段,给网络安全管理者,带来严峻的考验.网络安全的战场已经从互联网蔓延到用户内部的网络,特别是局域网.目前利用ARP欺骗的木马病毒在局域网中广泛传播,导致网络随机掉线甚至整体瘫痪,通讯被窃听,信息被篡改等严重后果. 0x2  ARP协议概述 ARP协议(address resolution protocol)地址解析协议 一台主机和另一台主机通信,要知道目标的IP地址,但是在局域网中传输数据的网卡却不能直接识别IP地址,所以用ARP解析协议将I

JavaScript mapreduce工作原理简析_基础知识

谷歌在2003到2006年间连续发表了三篇非常有影响力的文章,分别是2003年在SOSP上发布的GFS,2004年在OSDI上发布的MapReduce,以及2006年在OSDI上发布的BigTable.GFS是文件系统相关的,其对后来的分布式文件系统设计具有指导意义:MapReduce是一种并行计算的编程模型,用于作业调度:BigTable是一个用于管理结构化数据的分布式存储系统,构建在GFS.Chubby.SSTable等Google技术之上.相当多的Google应用使用了这三种技术,比如Go

搜索引擎原理简析 不懂搜索引擎原理的SEOer就是在裸奔

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 不懂搜索引擎原理的SEOer就是在裸奔. 嗯,在结束废话之前,再插一句:中国第一个基于网页索引搜索的搜索引擎是北大的天网. 好,先上图来简单看下搜索引擎的"三板斧":数据搜集->预处理[索引]->排名. 数据搜集 即数据的搜集阶段,将网页从浩如瀚海的9201.html">互联网世界搜集到自己的数