C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。

委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。

委托的声明(没有方法体的函数加上delegate关键字):

        /// <summary>
/// 无参委托
/// </summary>
public delegate void DelegaetNoReturnPara();
/// <summary>
/// 有参委托
/// </summary>
/// <param name="num"></param>
public delegate void DelegatePara(int num);
/// <summary>
/// 有参带返回值的委托
/// </summary>
/// <param name="num"></param>
public delegate int DelegateParaNumber(int num);
/// <summary>
/// 泛型委托
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public delegate T DelegateGeneric<T>(T t);

我们用反编译工具查看一下

用反编译工具可以看到委托是一个密闭的方法并且继承于[System.Runtime]System.MulticastDelegate,委托有一个构造函数,带有Invoke、BeginInvoke、EndInvoke三个方法。

委托既然是类,那我们也可对其进行实例化

        public static void GetData(int num)
{
Console.WriteLine($"调用了{nameof(GetData)}方法");
} public delegate void DelegatePara(int num); static void Main(string[] args)
{
Customer.GetData();
//委托的实例化必须传递一个方法,这个方法的返回值和参数必须和实例化的这个委托一致
//把方法包装成变量,Invoke的时候自动执行方法
DelegatePara noReturnPara = new DelegatePara(Customer.GetData);
noReturnPara.Invoke(1);//调用委托
noReturnPara(1);
}

在这里可能有同学会想,为什么不直接调用方法呢?ok,接着往下看.

有一个student类和一个获取集合对象的一个方法.

public class Student
{
public string name { get; set; }
public int age { get; set; }
public string sex { get; set; }
} public async Task<List<Student>> GetAllStudents()
{
var result = new List<Student>();
for (int i = ; i < ; i++)
{
result.Add(new Student
{
age = + i,
name = $"橘猫{i}",
sex = i / == ? "男" : "女"
});
}
return result;
}

假如现在有三个判断条件筛选集合中的内容

/// <summary>
/// 查询name的长度大于2的同学
/// </summary>
/// <returns></returns>
public async Task<List<Student>> GetStudents()
{
var result = new List<Student>();
var data = await this.GetAllStudents();
foreach (var item in data)
{
if (item.name.Length > )
result.Add(item);
}
return result;
}
/// <summary>
/// 查询年龄大于18岁的同学
/// </summary>
/// <returns></returns>
public async Task<List<Student>> GetStudents()
{
var result = new List<Student>();
var data = await this.GetAllStudents();
foreach (var item in data)
{
if (item.age > )
result.Add(item);
}
return result;
}
/// <summary>
/// 查询年龄大于18岁并且是女生的同学
/// </summary>
/// <returns></returns>
public async Task<List<Student>> GetStudents()
{
var result = new List<Student>();
var data = await this.GetAllStudents();
foreach (var item in data)
{
if (item.age > && item.sex.Equals("女"))
result.Add(item);
}
return result;
}

三个判断条件要写三个方法是不是太冗余了,我们直接写在一个方法里,根据条件类型来筛选数据

/// <summary>
/// 根据type来查询
/// </summary>
/// <returns></returns>
public async Task<List<Student>> GetStudents(int type)
{
var result = new List<Student>();
var data = await this.GetAllStudents();
switch (type)
{
case :
foreach (var item in data)
{
if (item.name.Length > )
result.Add(item);
}
break;
case :
foreach (var item in data)
{
if (item.age > )
result.Add(item);
}
break;
case :
foreach (var item in data)
{
if (item.age > && item.sex.Equals("女"))
result.Add(item);
}
break;
default:
Console.WriteLine("查询的类型有误,请重新输入");
break;
}
return result;
}

这样的话行是行,但是如果在多加一个条件呢?那么我们可不可以将判断逻辑传到方法里,只需返回true或false就行了.

//定义委托
public delegate bool judge(Student student);

//用来判断姓名
public bool judgeName(Student student)
{
return student.name.Length > ;
}
//用来判断年龄
public bool judgeAge(Student student)
{
return student.age > ;
}
//用来判断年龄和性别
public bool judgeAgeAndSex(Student student)
{
return student.age > && student.sex.Equals("女");
}
/// <summary>
/// 将判断逻辑传递过来
/// 委托解耦,减少重复代码,将公共逻辑当成变量传递过来
/// </summary>
/// <returns></returns>
public async Task<List<Student>> GetStudents(judge judge)
{
var result = new List<Student>();
var data = await this.GetAllStudents();
foreach (var item in data)
{
if (judge.Invoke(item))
result.Add(item);
}
return result;
}

有同学会说,你这代码也不精简,为什么不用lamda.这里的话主要是想告诉大家委托的作用,侧重点不同,望理解。

多播委托:

public delegate void DelegatePara(int num);
//这个委托实例只包含一个方法
DelegatePara noReturnPara = new DelegatePara(Customer.GetData);
//+= 为委托实例按顺序增加方法,形成方法链,依次执行
DelegatePara noReturnPara = new DelegatePara(Customer.GetData);
noReturnPara += new DelegatePara(Customer.GetData);
noReturnPara += new DelegatePara(new DelegateInstance().GetData);
noReturnPara.Invoke();//调用委托
//-= 为委托实例移除方法,从方法链的底部开始匹配,遇到第一个完全吻合的,移除且只移除一个
noReturnPara += new DelegatePara(Customer.GetData);
noReturnPara += new DelegatePara(new DelegateInstance().GetData);//这个去不掉,因为不是同一个实例中的方法
//循环获得委托中的实例
foreach (var item in noReturnPara.GetInvocationList())
{
item.DynamicInvoke();//调用委托
}

多播委托如果带返回值,结果以最后的为准。

事件:是带event关键字的委托实例,event可以限制变量被外部调用/直接赋值

public delegate void HandleEvent(int num);
public event HandleEvent handleEvent;
public void DelegateEvent()
{
handleEvent = new HandleEvent(Customer.GetData);
handleEvent.Invoke();
}

如果不是在本身所在的类中调用(事件)会如何呢?

很明显报错了

只能像下面这样写

DelegateInstance delegateInstance = new DelegateInstance();
delegateInstance.handleEvent += new DelegateInstance.HandleEvent(Customer.GetData);
Console.ReadKey();

这里需要说一下:Event+委托的一个实例,加上一个event关键字限制了外部调用权限,保证其安全(不能再其它类中调用和赋值,只能用来添加和移除注册方法),在本身类中可以调用和赋值,但是在子类中也不可以调用和赋值.

委托与事件的区别和联系:委托是一个类型(委托的本质是一个类);事件是委托类型的一个实例.

ok,今天先到这儿。如有不足的地方,望见谅。

C# 委托浅析的更多相关文章

  1. C#委托及事件处理机制浅析

    事件可以理解为某个对象所发出的消息,以通知特定动作(行为)的发生或状态的改变.行为的发生可能是来自用户交互,如鼠标点击:也可能源自其它的程序逻辑.在这里,触发事件的对象被称为事件(消息)发出者(sen ...

  2. 浅析C#之委托、Action、Func

    一.委托 1.1 委托的定义 delegate(委托)是一种可用于封装命名方法或匿名方法的引用类型, 委托类似于 C++ 中的函数指针: .Net通过委托来提供回调函数机制. 声明一个委托类型 int ...

  3. c#委托之浅析

    前言: 这章我们将弄懂,委托是什么?有什么作用?在什么样的场景下可以启到什么作用? 委托适用的场景:当确定处理一个任务时,不确定其处理任务的方法时可使用,这样可以提高扩展性,调用符合条件的处理方法,避 ...

  4. 读书笔记 C#委托的BeginInvoke、EndInvoke之浅析

    c#中有一种类型叫委托,它是一种引用类型.可以引用静态与非静态的方法,且这些方法的参数列表和返回值类型必须与所声明的委托一致. 委托引用的方法可以通过BeginInvoke和EndInvoke来异步进 ...

  5. c#进阶之浅析委托和事件

    何为委托 加了delegate关键字,没有方法体{}的方法模版(方法列表);委托是一种类型 public void Write() { //TODO } //加上关键字delegate,去掉方法体{} ...

  6. C#回调浅析(委托、接口回调)

    https://wenku.baidu.com/view/ed724173bd64783e08122b2f.html

  7. 【深入浅出jQuery】源码浅析2--奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  8. Reactive Extensions(Rx)并发浅析

    Reactive Extensions(Rx)并发浅析 iSun Design & Code .Net并行编程 - Reactive Extensions(Rx)并发浅析 关于Reactive ...

  9. C# Winform窗口之间传值的多种方法浅析(转)

    摘要http://www.jb51.net/article/63837.htm 这篇文章主要介绍了C# Winform窗口之间传值的多种方法浅析,本文起讲解了通过构造器传值.通过属性传递.通过事件携带 ...

随机推荐

  1. tomcat8调优

    a. tomcat的运行原理: 1. Tomcat是运行在JVM中的一个进程.它定义为[中间件],顾名思义,是一个在Java项目与JVM之间的中间容器. 2. Web项目的本质,是一大堆的资源文件和方 ...

  2. ubuntu 和 centos 如何区分系统

    Ubuntu Ubuntu有着漂亮的用户界面,完善的包管理系统,强大的软件源支持,丰富的技术社区,Ubuntu还对大多数硬件有着良好的兼容性,包括最新的图形显卡等等.这一切让Ubuntu越来越向大众化 ...

  3. Dubbo(六):zookeeper注册中心的应用

    Dubbo中有一个非常本质和重要的功能,那就是服务的自动注册与发现,而这个功能是通过注册中心来实现的.而dubbo中考虑了外部许多的注册组件的实现,zk,redis,etcd,consul,eurek ...

  4. LTE无线网络优化简介

    LTE无线网络优化特点 覆盖和质量的估计参数不同 TD-LTE使用RSPP.RSRQ.SINR进行覆盖和质量的评估. 影响覆盖问题的因素不同 工作频段的不同,导致覆盖范围的差异显著:需要考虑天线模式对 ...

  5. maven项目变成web项目

    具体步骤如图所示: 第一步:建议一个Maven Webapp项目  第二步:右击项目,选择属性,找到project facets,点击tuntimes标签选择apache tomcat v6.0选中P ...

  6. 【MySQL基础总结】索引的使用

    索引的使用 概述 1.索引由数据库中一列或多列组合而成,其作用是提高对表中数据的查询速度 2.索引的优点是可以提高检索数据的速度 3.缺点是创建和维护索引需要耗费时间 4.所以索引可以提高查询速度,减 ...

  7. [hdu4629 Burning]三角形面积并,扫描线

    题意:给n个三角形,分别求覆盖1次~n次的总面积 思路: 对每个y坐标作一条平行于x轴的直线,按直线从下往上处理,每两条直线之间为若干梯形(也可以是三角形)首尾相连的情况,从左扫到右时,用一个变量cn ...

  8. [csu/coj 1083]贪心

    题意:给定n个线段,问能不能把x,y,z个长度为1,2,3的线段不重合地放进去. 思路:首先如果n个线段长度比要放的长度之和小,则无解,否则先考虑放2和3,如果2和3放下了1肯定可以放下(这是显然的) ...

  9. windows中的项目拷贝到linux中,部分数据不显示的原因

    linux严格区分大小写,可能是数据表名大小写导致的. 如上传文件不成功,可能是系统权限导致的.

  10. 相机测试camera报告的问题

    AE问题 整体偏亮 整体偏暗 高光过爆 暗处过暗 对比度低/高 亮度: 关注暗处过暗 高光过爆   对比度: 关注头发,衣服 对比度低照片会有好像一层薄薄的,发蒙 关注植物,会有灰色的 AWB问题 偏 ...