c# 委托的常见用法
作者:厉致彤 发布时间:2021-08-11 13:44:05
此篇文章是我一个小白对委托的理解和总结,请高手多多评判指教。
委托就是一种后期绑定机制,说的直白点就是在调用的时候才去传递业务逻辑的一种算法。
委托的创建语法:
public delegate int Comparison<in T>(T left, T right);//官方给出的定义泛型委托的demo
语法看似像声明一个变量或方法的签名,但实现上是在声明一个类型。编译器会生成一个派生自System.MulticastDelegate的类(而System.MulticastDelegate派生自System.Delegate),类型名与委托的名字相同,其中包含Invoke 、BeginInvoke和EndInvoke等方法。编译器还为这个新类型生成添加和删除处理业务,以便该类的客户端可以在实例的调用列表中添加和删除方法。
委托可以被定义在类的内部、名称空间下(与类同级)和全局名称空间下(不推荐)。
//在全局定义
public delegate int Comparison<in T>(T left, T right);
namespace Test
{
//在指定名称空间下定义
public delegate int Comparison2<in T>(T left, T right);
public class Student
{
//在类内部定义
public delegate int Comparison3<in T>(T left, T right);
}
}
委托的定义赋值
将委托当成类使用(委托本身就是一个类)。
//定义委托
public delegate int Comparison<in T>(T left, T right);
public class Test
{
//定义
private Comparison<int> comparator;
public void Show()
{
//赋值 请注意,使用的是方法名称,不带括号,将方法附加给委托作为委托的调用方法。
this.comparator = Compare;
//调用
this.comparator(1, 2);//调用方式二 this.comparator.Invoke(1, 2);
}
private int Compare(int left, int right) => left.CompareTo(right);
}
当用作委托的目标方法是“小方法”的情况下,通常使用lambda表达式语法来执行赋值:
Comparison<string> comparer = (left, right) => left.Length.CompareTo(right.Length);
多播委托
通常只是将单个目标方法附加到委托。但是,委托对象确实支持将多个目标方法附加到一个委托对象的调用列表,称为多播委托。多播委托意味着通过委托调用时可以调用多个方法,所以可以为委托附加多个方法。
private int Cal(int num) {return num * num;}
private void button1_Click(object sender, EventArgs e)
{
Func<int, int> action = null;
//使用+= 或 -= 来增加或移除委托实例
action += a => { Console.WriteLine($"第{1}次执行" + a); return a + 1; };
action += Cal;
action += a => { Console.WriteLine($"第{3}次执行" + a); return a + 3; };
action -= Cal;
//如果有返回值的话,返回的是最后一次执行的结果
int a = action(5);
Console.WriteLine(a);
}
常用泛型委托
无返回值
public delegate void Action();
public delegate void Action<in T>(T arg);
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
// Other variations removed for brevity.
有返回值
public delegate TResult Func<out TResult>();
public delegate TResult Func<in T1, out TResult>(T1 arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
// Other variations removed for brevity
返回bool类型
public delegate bool Predicate<in T>(T obj);
注意:在.net core平台中,不支持委托目标方法的异步调用(即不支持BeginInvoke方法):
Action action = () => Console.WriteLine("委托执行了");
AsyncCallback asyncCallback = a => Console.WriteLine("回调执行了" + a);
//System.PlatformNotSupportedException:“Operation is not supported on this platform.”
IAsyncResult result = action.BeginInvoke(asyncCallback, "asdf"); //委托启动异步调用
action.EndInvoke(result);
Event 事件
事件是带event关键字的委托的实例,event可以限制被外部调用(invoke)和直接赋值(=)。委托是一个类型,而事件是委托类型的一个实例。
声明一个事件很简单,只需在声明一个委托对象时加上event关键字就行。
/// <summary>
/// 定义一个委托
/// </summary>
/// <param name="name"></param>
public delegate void ShowInfo(string name);
public class Study
{
/// <summary>
/// 声明一个事件
/// </summary>
public event ShowInfo ShowInfo;
public void Show()
{
ShowInfo += Study_ShowInfo;
//只能在“publisher”类中调用
ShowInfo("asdf");
}
private void Study_ShowInfo(string name)
{
throw new NotImplementedException();
}
}
可以在用事件的地方用委托来替代,但事件有一系列规则和约束用以保证程序的安全可控,事件只有 += 和 -= 操作,这样订阅者只能有订阅或取消订阅操作,没有权限执行其它操作。如果是委托,那么订阅者就可以使用 = 来对委托对象重新赋值(其它订阅者全部被取消订阅),甚至将其设置为null,甚至订阅者还可以直接调用委托,这些都是很危险的操作,广播者就失去了独享控制权。
事件保证了程序的安全性和健壮性。
来源:https://www.cnblogs.com/lizhitong/p/13502038.html
猜你喜欢
- 质数又称素数。一个大于1的自然数,如果除了1和它自身外,不能被其他自然数整除的数;否则称为合数。根据算术基本定理,每一个比1大的整数,要么本
- 一、spring-boot-devtools在pom中直接引入依赖<dependency> <groupId&
- 问题当我们数据库中的字段和实体类中的字段不一致的时候,查询会出问题数据库字段是 pwdid name pwd1 张三 1234562 李四
- 前言我们在实际项目中,除了会碰到一对一的情况,还有一对多的情况,比如一个用户可以有多辆车,而一辆车只能有一个用户等等,今天我们就来一起学习下
- 配置文件context-path的坑context-path: /manage 这个配置加入后会导致访问spring的页面都需要加这个/ma
- 基本原理:利用URLConnection获取要下载文件的长度、头部等相关信息,并设置响应的头部信息。并且通过URLConnection获取输
- 1. 在原有工程目录右键-> new ->Module->:2. 选择library:3. 一路next,最后finish
- 二分法查找,顾名思义就是要将数据每次都分成两份然后再去找到你想要的数据,我们可以这样去想,二分法查找很类似与我们平时玩的猜价格游戏,当你报出
- mysql实现配置中心本公司配置数据的管理是通过mysql进行配置管理,因为已经搭建好了,所以自己动手重新搭建一遍,熟悉整个流程。有关项目源
- 什么是volatile关键字volatile是Java中用于修饰变量的关键字,其可以保证该变量的可见性以及顺序性,但是无法保证原子性。更准确
- 一、 * 与过滤器在讲Spring boot之前,我们先了解一下过滤器和 * 。这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较
- 在编写类的时候可以使用两种方式定义类:public class定义类:class定义类:如果一个类声明的时候使用了public class进
- Java中重载与重写的区别首先我们来讲讲:重载(Overloading) (1) 方法重载是让类以统一的
- Spring 中bean的获取1.通过context.getbean 的方式来获取beanApplicationContext:是sprin
- 本文实例讲述了C#不重复输出一个数组中所有元素的方法。分享给大家供大家参考。具体如下:1.算法描述0)输入合法性校验1)建立临时数组:与原数
- kotlin基础教程之类和继承类声明使用class关键字声明类,查看其声明格式:: modifiers ("class"
- 一、什么是网关限流:在微服务架构中,网关层可以屏蔽外部服务直接对内部服务进行调用,对内部服务起到隔离保护的作用,网关限流,顾名思义,就是通过
- 方法一:使用AnimatedGif库Nuget安装包:Install-Package AnimatedGif -Version 1.0.5h
- 创建新的项目的时候,文件名一直追加,不分层对于刚用idea的小白,这个问题困扰了我好几天了,幸好现在还不怎么敲代码,下面给一个详细的解决方案
- 本博文将为您提供自Java 7以来增加的很棒的新功能的示例。我将展示每个Java版本的至少一项重大改进,一直到2020年秋季发布的Java