深入理解C# 委托(delegate)-戈多编程
今天来谈谈委托,深入理解委托,本文来自各大神经验总结。
1.委托是什么?
委托类型的声明与方法签名相似。 它有一个返回值和任意数目任意类型的参数,是一种可用于封装命名方法或匿名方法的引用类型。 委托类似于 C++ 中的函数指针;但是,委托是类型安全和可靠的。
(1)从数据结构来讲,委托和类一样是一种用户自定义类型
(2)从设计模式来讲,委托(类)提供了方法(对象)的抽象
既然委托是一种类型,那么它存储的是什么数据?
我们知道,委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址。调用委托的时候,委托包含的所有方法将被执行。
2.委托类型的定义
委托是类型,就好像类是类型一样。与类一样,委托类型必须在被用来创建变量以及类型对象之前声明。
delegate void MyDel(int x);
委托类型声明:
(1) 以deleagate关键字开头。
(2)返回类型+委托类型名+参数列表。
3.申明委托变量
MyDel del1,del2;
4.初始化委托变量
(1)使用new运算符
new运算符的操作数的组成如下:
- 委托类型名
- 一组圆括号,其中包含作为调用列表中的第一个成员的方法的名字。方法可以是实例方法或静态方法。
del1 = new MyDel( myInstObj.MyM1 );
del2 = new MyDel( SClass.OtherM2 );
(2)使用快捷语法
del1 = myInstObj.MyM1;
del2 = SClass.OtherM2;
5.赋值委托
由于委托是引用类型,我们可以通过给它赋值来改变包含在委托变量中的方法地址引用。旧的引用会被垃圾回收器回收。
MyDel del;
del = myInstaObj.MyM1; //委托初始化
del = SClass.OtherM2;//委托重新赋值,旧的引用将被回收
6.组合委托
委托可以使用额外的运算符来组合。这个运算最终会创建一个新的委托,其调用列表是两个操作数的委托调用列表的副本的连接。
委托是恒定的,操作数委托创建后不会被改变。委托组合拷贝的是操作数的副本。
MyDel del1 = myObj.MyMethod;
MyDel del2 = SClass.OtherM2;
MyDel del3 = del1 + del2; //组合调用列表
7.委托加减运算
可以使用+=运算符,为委托新增方法。
同样可以使用-=运算符,为委托移除方法。
MyDel del = myObj.MyMethod;
del += SClass.OtherM2; // 增加方法
del -= myObj.MyMethod; // 移除方法
8.委托调用
委托调用跟方法调用类似。委托调用后,调用列表的每个方法将会被执行。
在调用委托前,应判断委托是否为空。调用空委托会抛出异常。
if(null != del)
{
del();//委托调用
}
9.匿名方法
匿名方法是在初始化委托时内联声明的方法。
基本结构:
deleage( 参数 ) { 语句块 }
例如:
delegate int MyDel (int x); //定义一个委托
MyDel del = delegate( int x){ return x; };
从上面我们可以看到,匿名方法是不会显示声明返回值的。
10.Lambda表达式
ambda表达式主要用来简化匿名方法的语法。在匿名方法中,delegate关键字有点多余,因为编译器已经知道我们将方法赋值给委托。通过几个简单步骤,我们就可以将匿名方法转换为Lambda表达式:
- 删除delegate关键字
- 在参数列表和匿名方法主体之间防Lambda运算符=>。Lambda运算符读作"goes to"
MyDel del = delegate( int x) { return x; };//匿名方法
MyDel del2 = (int x) => {return x;};//Lambda表达式
MyDel del3 = x => {return x};//简写的Lambda表达式
11.委托示例
public class Test
{
//定义委托
public delegate void D_Math(int a, int b);
public void Add(int a, int b)
{
Console.WriteLine("Add方法结果:{0}", a + b);
}
public void Cut(int a, int b)
{
Console.WriteLine("Cut方法结果:{0}", a - b);
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Test t = new Test();
Test.D_Math D = new Test.D_Math(t.Add);//委托实例化,也可Test.D_Math D =t.Add;
D += t.Cut;//委托可以以队列方式执行多个方法,以+=运算符或者-=来增加或者取消队列中的方法
D(5, 6);
}
}
以上看出来委托实用的地方了吗?即委托可以执行任何引入参数类型相同且返回类型相同的方法,甚至可以执行签名相同的方法队列。
那么我们的方法签名(即引入参数和输出参数)真的必须与委托完全一致吗?答:不是的,我们不能忽略协变与逆变。
我们这里简单介绍一下协变与逆变的知识。
“协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。
“逆变”则是指能够使用派生程度更小的类型。
那么,我们的委托也是接受协变与逆变的。
意思是,如果定义一个delegate,那么不仅仅签名完全相同的方法可以赋值给delegate变量。
如果一个方法的参数表符合delegate声明,但返回的类型是(delegate声明返回类型)的派生类,那也可以将这个方法赋值给这个delegate变量。
如果一个方法的返回类型符合delegate的声明,但参数是(delegate声明参数类型)的祖先类,那也可以将这个方法赋值给这个delegate变量。
如果一个方法的参数和返回类型都符合上面两行的假设,那也可以将这个方法赋值给这个delegate变量。
以下以两个简单示例解释协变与逆变:
协变:
public class A { }
public class B:A { }//B继承自A
public class Test
{
//定义委托
public delegate A D_Math();
public B Add()
{
return new B();
}
public A Add2()
{
return new A();
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Test.D_Math d = new Test.D_Math(new Test().Add);//委托返回A,而Add方法返回B,此为协变。
}
}
逆变:
public class A { }
public class B:A { }//B继承自A
public class Test
{
//定义委托
public delegate void D_Math(B b);
public void Add(B b)
{
}
public void Add2(A a)
{
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Test.D_Math d = new Test.D_Math(new Test().Add2);//委托引入参数B,而Add方法参数为A类型,此为协逆变。
}
}
深入理解C# 委托(delegate)-戈多编程的更多相关文章
- 深入理解委托(Delegate)
前言 委托其实一直以来都感觉自己应该挺熟悉的,直到最近又去翻了翻 CLR via C#,感觉我之前的理解可能还有失偏颇.在这记录一下. 之前文章的链接: 接口和委托的泛型可变性 C#高级编程笔记 De ...
- 理解委托(delegate)及为什么要使用委托
理解委托(delegate)及为什么要使用委托 委托:是一种定义方法签名的类型. 当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联. 您可以通过委托实例调用方法. 上述为官方说法,理解起来 ...
- 关于C# 委托(delegate)与事件(event)的用法及事例
C#中的委托和事件对于新手可能会有一点难理解,所以先从一个小例子入手,以便能更好的理解其如何使用.有一个学生每天定闹钟在早上6点起床,所以当每天早上6点的时候,闹钟就会响起来,从而学生才会按时起床. ...
- [.NET] C# 知识回顾 - 委托 delegate (续)
C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...
- C# 委托Delegate(一) 基础介绍&用法
本文是根据书本&网络 前人总结的. 1. 前言 定义&介绍: 委托Delegate是一个类,定义了方法的类型, 使得可以将方法当做另一个方法的参数来进行传递,这种将方法动态地赋给参数的 ...
- C#基础知识六之委托(delegate、Action、Func、predicate)
1. 什么是委托 官方解释 委托是定义方法签名的类型,当实例化委托时,您可以将其实例化与任何具有兼容签名的方法想关联,可以通过委托实例调用方法. 个人理解 委托通俗一点说就是把一件事情交给别人来帮助完 ...
- CLR via C#(12)-委托Delegate
本来按照进度应该学习事件了,可总觉得应该委托在前,事件在后,才好理解. 委托是一个类,它提供了回调函数机制,而且是类型安全的.使用委托可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数 ...
- C# 代理/委托 Delegate
本文转载自努力,努力,努力 1. 委托的定义:委托是函数的封装,它代表一"类"函数.他们都符合一定的签名:拥有相同的参数列表,返回值类型.同时,委托也可以看成是对函数的抽象,是函数 ...
- ch01.深入理解C#委托及原理(转)
ch01..深入理解C#委托及原理_<没有控件的ASPDONET> 一.委托 设想,如果我们写了一个厨师做菜方法用来做菜,里面有 拿菜.切菜.配菜.炒菜 四个环节,但编写此方法代码的人想让 ...
- c# 委托 delegate
委托是一种存储函数引用的类型,在事件和事件的处理时有重要的用途 通俗的说,委托是一个可以引用方法的类型,当创建一个委托,也就创建一个引用方法的变量,进而就可以调用那个方法,即委托可以调用它所指的方法. ...
随机推荐
- redis数据库学习
0 使用理由 0.1 高性能 纯内存操作,比在硬盘操作数据的速度有极大提升 0.2 高并发 承受请求比直接操作数据库大得多 0.3 单线程 至于redis单线程的原因.有点意思.CPU不是Redis的 ...
- Hello, OpenWrite
目录 Markdown For Typora Overview Block Elements Paragraph and line breaks Headers Blockquotes Lists T ...
- 持续集成高级篇之Jenkins windows/linux混合集群搭建(二)
系列目录 前面我们说过,要使用ssh方式来配置windows从节点,如果采用ssh方式,则windows和linux配置从节点几乎没有区别,目前发现的惟一的区别在于windows从节点上目录要设置在c ...
- 从零开始开发IM(即时通讯)服务端(二)
好消息:IM1.0.0版本已经上线啦,支持特性: 私聊发送文本/文件 已发送/已送达/已读回执 支持使用ldap登录 支持接入外部的登录认证系统 提供客户端jar包,方便客户端开发 github链接: ...
- Android开发教程:开发框架基本原理
1.提供应用程序框架(Framework) 开发者可以遵照这些框架搭建应用程序读者可以结合J2SE平台的Applet框架或J2ME平台的移动信息设备套件框架来理解Android平台的应用程序框架. 每 ...
- 【学习笔记】python3核心技术与实践--开篇词
python的应用和流行程度: Python 可以运用在数据处理.Web 开发.人工智能等多个领域,它的语言简洁.开发效率高.可移植性强,并且可以和其他编程语言(比如 C++)轻松无缝衔接.现如今,不 ...
- FourAndSix2 靶机渗透
0x01 简介 FourAndSix2是易受攻击的一个靶机,主要任务是通过入侵进入到目标靶机系统然后提权,并在root目录中并读取flag.tx信息 FourAndSix2.镜像下载地址: https ...
- springcloud config配置读取优先级
情景描述 最近在修复Eureka的静态页面加载不出的缺陷时,最终发现是远程GIT仓库将静态资源访问方式配置给禁用了(spring.resources.add-mappings=false).虽然最后直 ...
- Game with string CodeForce#1104B 栈、串
题目链接:Game with string 题目原文 Two people are playing a game with a string
- opencv图像处理之常见滤波器
图像平滑 Smoothing, also called blurring, is a simple and frequently used image processing operation. 平滑 ...