04.委托Delegation
1. 基本了解
1.1 委托简述
官方文档
委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用,用于将方法作为参数传递给其他方法,可将任何可访问类或结构中与委托类型匹配的任何方法分配给委托
其它说明
委托在IL中就是一个类(本质上是类),继承与System.MulticastDelegate类(特殊类)
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递
委托类型
自定义委托:Delegate
系统内置委托:Action,Func
委托声明
可以声明在类的外部也可以在内部,在IL中,无论在内外都会编译到类的内部
委托在实例化时,需要传入一个方法,此方法返回值,参数(类型,个数,顺序)与委托一致
1.2 使用步骤
- 声明一个委托
- 委托的实例化,传入指定方法
- 调用执行
2. Delegate委托
Delegate:常用到的一种声明,且至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型
2.1 示例一:无参,无返回值
// 1.声明委托
public delegate void NoReturnNoPare();
// 2.准备委托执行方法
public void Show()
{
Console.WriteLine("无参,无返回值");
}
// 3.实例,调用委托
public void Start()
{
NoReturnNoPare d1 = new NoReturnNoPare(this.Show);
d1.Invoke();
}
2.2 示例二:有参,无返回值
// 1.声明委托
public delegate void NoReturnWithPare(int x, int y);
// 2.准备委托执行方法
public void Show(int x,int y)
{
Console.WriteLine("有参,无返回值");
}
// 3.实例,调用委托
public void Start()
{
NoReturnWithPare d2 = new NoReturnWithPare(this.Show);
d2.Invoke(1,2);
}
2.3 示例三:有参,有返回值
// 1.声明委托
public delegate int WithReturnWithPare(int x, int y);
// 2.准备委托执行方法
public int Show(int x, int y)
{
return x + y;
}
// 3.实例,调用委托
public void Start()
{
WithReturnWithPare d2 = new WithReturnWithPare(this.Show);
// 返回值类型,编译器会自动推断
int IResult = d2.Invoke(1, 2);
Console.WriteLine(IResult);
}
3. Action委托
Action是系统内置委托(无需声明),是无返回值的泛型委托,至少0个参数,至多16个参数,且无返回值
3.1 示例一:无参,无返回值
// 1.定义执行方法
public void Show()
{
Console.WriteLine("无参,无返回值");
}
// 2.调用执行
public void Start()
{
Action action = new Action(this.Show);
// Action<int, int> action = this.Show;
action.Invoke();
}
3.2 示例二:有参,无返回值
// 1.定义执行方法
public void Show(int x, int y)
{
Console.WriteLine("有参,无返回值");
}
// 2.调用执行
public void Start()
{
Action<int, int> action = new Action<int,int>(this.Show);
// Action<int, int> action = this.Show;
action.Invoke(1,2);
}
3.3 示例三:使用 lambda 表达式
Action<int, int> action = (x, y) => { };
action.Invoke(1, 2);
3.4 示例四:将委托作为方法参数
public void Start()
{
Action<int> action = (x) => { Console.WriteLine(x); };
Show(action, 2);
}
public void Show<T>(Action<T> ac, T inputParam)
{
ac(inputParam);
}
4. Func委托
Func是有返回值的泛型委托,至少0个参数,至多16个参数,根据返回值泛型返回;必须有返回值,不可void,且最后一位泛型类型,为返回值类型
4.1 示例一:无参,有返回值
public void Start()
{
Func<string> func = new Func<string>(this.Show);
string IResult = func.Invoke();
Console.WriteLine(IResult);
}
public string Show()
{
return "libai";
}
4.2 示例二:有参,有返回值
public void Start()
{
Func<int, string> func = new Func<int, string>(this.Show);
string IResult = func.Invoke(1);
Console.WriteLine(IResult);
}
public string Show(int i)
{
return "libai\t" + i;
}
4.3 示例三:使用lambda表达式
public void Start()
{
Func<int> func1 = () => { return 1; };
int IResultInt = func1.Invoke();
Console.WriteLine(IResultInt);
Func<int, string> func2 = (i) => { return i.ToString(); };
string IResult = func2.Invoke(1);
Console.WriteLine(IResult);
}
4.4 示例四:将委托作为方法参数
例子一:简化
public void Start()
{
Func<int, int, int> func = (x, y) => { return x + y; };
int IResultInt = Test(func, 1, 2);
Console.WriteLine(IResultInt);
}
public int Test<T1, T2>(Func<T1, T2, int> func, T1 a, T2 b)
{
return func(a, b);
}
示例二:一般写法
static void Main(string[] args)
{
Console.WriteLine(Test<int,int>(Fun,100,200));
Console.ReadKey();
}
public static int Test<T1, T2>(Func<T1, T2, int> func, T1 a, T2 b)
{
return func(a, b);
}
private static int Fun(int a, int b)
{
return a + b;
}
5. 链式委托
5.1 文档说明
官方文档
委托对象的一个有用属性在于可通过使用 + 运算符将多个对象分配到一个委托实例,多播委托包含已分配委托列表,此多播委托被调用时会依次调用列表中的委托;仅可合并类型相同的委托
-运算符可用于从多播委托中删除组件委托,顺序,从下至上(委托列表中没有移除的委托时不会报错)+运算符可用于将委托组件添加到委托列表,顺序,从上而下
在执行有返回值的委托链时,只能得到最后一个委托的结果
其它文档
委托链(多播委托)是一个由委托组成的链表,而不是一个新的东西,所有的自定义委托都直接集成自System.MulticastDelegate类型,这个类型即是为委托链而设计的
链式委托是指一个委托的链表,而不是指另外一类特殊的委托,当执行链上的一个方法时,后续委托将会被依此执行
System.MuticastDelegate定义了对链式委托的支持,在System.Delegate的基础上,增加了一个指向后续委托的指针,这样就实现了一个简单的链表结构
5.2 示例一:统一执行
public void Start()
{
NoReturnWithPare noReturnWith = new NoReturnWithPare(this.Fun1);
noReturnWith += this.Fun2;
noReturnWith += this.Fun1;
noReturnWith.Invoke(1, 2);
}
public void Fun1(int x, int y)
{
Console.WriteLine("Fun1:\t" + x + y);
}
public void Fun2(int x, int y)
{
Console.WriteLine("Fun2:\t" + x + y);
}
5.3 示例二:逐个执行
注意:逐个执行时,单项不能用var声明,必须使用委托的具体类型
逐个指定,返回值,问题,b委托使用a的返回值?
public void Start()
{
NoReturnWithPare noReturnWith = new NoReturnWithPare(this.Fun1);
noReturnWith += this.Fun2;
noReturnWith += this.Fun1;
foreach (NoReturnWithPare item in noReturnWith.GetInvocationList())
{
item.Invoke(1,2);
}
}
public void Fun1(int x, int y)
{
Console.WriteLine("Fun1:\t" + x + y);
}
public void Fun2(int x, int y)
{
Console.WriteLine("Fun2:\t" + x + y);
}
5.4 示例三:责任链模式
典型案例:用代码模拟,猫叫了,狗叫了,然后老鼠跑了
普通实现
using System;
namespace de2
{
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.Miao();
}
}
public class Cat
{
public void Miao()
{
Console.WriteLine("猫叫了");
new Dog().Wang();
new Mouse().Run();
}
}
public class Dog
{
public void Wang()
{
Console.WriteLine("狗叫了");
}
}
public class Mouse
{
public void Run()
{
Console.WriteLine("老鼠跑了");
}
}
}
使用责任链模式实现(委托)
using System;
namespace de2
{
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.miaoAction += new Dog().Wang;
cat.miaoAction += new Mouse().Run;
cat.MiaoDelegate();
}
}
public class Cat
{
public void Miao()
{
Console.WriteLine("猫叫了");
}
public Action miaoAction;
public void MiaoDelegate()
{
this.Miao();
this.miaoAction.Invoke();
}
}
public class Dog
{
public void Wang()
{
Console.WriteLine("狗叫了");
}
}
public class Mouse
{
public void Run()
{
Console.WriteLine("老鼠跑了");
}
}
}
使用责任链模式实现(抽象方法)
using System;
using System.Collections.Generic;
namespace de2
{
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.Add(new Dog());
cat.Add(new Mouse());
cat.AbsServer();
}
}
public interface IAbsServer
{
void Do();
}
public class Cat : IAbsServer
{
private List<IAbsServer> list = new List<IAbsServer>();
public void Add(IAbsServer absServer)
{
list.Add(absServer);
}
public void AbsServer()
{
this.Do();
foreach (var item in list)
{
item.Do();
}
}
public void Miao()
{
Console.WriteLine("猫叫了");
}
public void Do()
{
this.Miao();
}
}
public class Dog : IAbsServer
{
public void Do()
{
this.Wang();
}
public void Wang()
{
Console.WriteLine("狗叫了");
}
}
public class Mouse : IAbsServer
{
public void Do()
{
this.Run();
}
public void Run()
{
Console.WriteLine("老鼠跑了");
}
}
}
使用责任链模式实现(事件)
using System;
namespace de2
{
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.miaoEvent += new Dog().Wang;
cat.miaoEvent += new Mouse().Run;
cat.MiaoEvent();
}
}
public class Cat
{
public void Miao()
{
Console.WriteLine("猫叫了");
}
/// <summary>
/// 事件,只能在事件所在类(本身类,子类不可)的内部 Invoke 执行
/// </summary>
public event Action miaoEvent;
public void MiaoEvent()
{
this.Miao();
this.miaoEvent.Invoke();
}
}
public class Dog
{
public void Wang()
{
Console.WriteLine("狗叫了");
}
}
public class Mouse
{
public void Run()
{
Console.WriteLine("老鼠跑了");
}
}
}
5.5 补充说明
链式委托的执行顺序是:按照委托链上的顺醋从当前委托开始依次往后执行,如果有需要可以使用GetInvocationList()方法来获得委托链上所有需要执行的委托,并且按照任何希望的顺序去逐个执行(Invoke)
委托可以是带有返回值的方法,但多余一个带返回值的方法被添加到委托链中时,程序员需要手动地调用委托链上的每个方法,否则委托使用者智能得到委托链上最后一个被执行的方法的返回值
委托的应用场合通常是任务的执行者把细节工作进行再分配,执行者确切地知道什么工作将要被执行,但却把执行细节委托给其他组件、方法或者程序集
6. 委托事件
事件(Event):是委托的实例,在定义委托是加了enevt 关键字
enevt 关键字,限定权限,只能在事件所在类中调用事件
6.1 示例一:自定义标准事件
模拟:用户订阅手机降价事件,当降价时用于购买手机
using System;
namespace de3
{
class Program
{
static void Main(string[] args)
{
Phone phone = new Phone
{
name = "vivo",
Price = 1999
};
phone.DiscountEventHandler += new User() { name = "李白" }.Buy;
phone.Price -= 400;
}
}
// 事件额外信息
public class EventPara
{
public int oValue { get; set; }
public int nValue { get; set; }
}
public delegate void CostomEventHandler(object sender, EventPara para);
// 手机,发布者,发布事件并且在满足条件情况下执行事件
public class Phone
{
public string name { get; set; }
private int price;
public int Price
{
set
{
if (value < this.price)
{
this.DiscountEventHandler?.Invoke(this, new EventPara
{
oValue = this.price,
nValue = value
});
}
this.price = value;
}
get { return this.price; }
}
public event CostomEventHandler DiscountEventHandler;
}
// 订户,关注事件,事件发生后执行动作
public class User
{
public string name { get; set; }
// 买手机
public void Buy(object sender, EventPara para)
{
Phone phone = (Phone)sender;
Console.WriteLine($"手机:{phone.name}\t打折前:{para.oValue}\t打折后:{para.nValue}");
Console.WriteLine("购买手机!");
}
}
}
标注:委托事件实际应用还不太熟,示例做参考即可
7. 扩展补充
7.1 委托的内部结构
IL语言的无参无返回值的委托结构(编译后)
.class nested public auto ansi sealed NoReturnNoPare
extends [mscorlib]System.MulticastDelegate
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method NoReturnNoPare::.ctor
.method public hidebysig newslot virtual
instance void Invoke () runtime managed
{
} // end of method NoReturnNoPare::Invoke
.method public hidebysig newslot virtual
instance class [mscorlib]System.IAsyncResult BeginInvoke (
class [mscorlib]System.AsyncCallback callback,
object 'object'
) runtime managed
{
} // end of method NoReturnNoPare::BeginInvoke
.method public hidebysig newslot virtual
instance void EndInvoke (
class [mscorlib]System.IAsyncResult result
) runtime managed
{
} // end of method NoReturnNoPare::EndInvoke
} // end of class NoReturnNoPare
7.2 调用委托
使用委托实例调用,参数写在括号中
NoReturnNoPare d1 = new NoReturnNoPare(this.Show);
d1();
使用实例的
Invoke()方法调用,参数写在方法中
NoReturnNoPare d1 = new NoReturnNoPare(this.Show);
d1.Invoke();
7.3 Predicate<T>委托
说明:不常用,仅作为了解(看个人情况)
Predicate是返回bool型的泛型委托,至少1个参数,至多1个参数,返回值固定为bool
官方示例
using System;
using System.Drawing;
public class Example
{
public static void Main()
{
Point[] points = { new Point(100, 200),
new Point(150, 250), new Point(250, 375),
new Point(275, 395), new Point(295, 450) };
Predicate<Point> predicate = FindPoints;
Point first = Array.Find(points, predicate);
Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
}
private static bool FindPoints(Point obj)
{
return obj.X * obj.Y > 100000;
}
}
04.委托Delegation的更多相关文章
- 委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托, 调用委托链方法,委托链异常处理
委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链.本篇的话题包括:委托链是怎样形成的,如何调用委托链方法,以及委托链异常处理. □ 调用返回类型为 ...
- 大话设计模式--委托--IOS
最近看了一些关于IOS委托的文章,看完之后,感觉不大好. 引文: 委托delegation是一种简单但是功能强大的设计模式,它的功能是程序中一个对象代表另一个对象,或者一个对象与另外一个对象协同工作. ...
- 委托、Lambda表达式、事件系列07,使用EventHandler委托
谈到事件注册,EventHandler是最常用的. EventHandler是一个委托,接收2个形参.sender是指事件的发起者,e代表事件参数. □ 使用EventHandler实现猜拳游戏 使用 ...
- 委托、Lambda表达式、事件系列06,使用Action实现观察者模式,体验委托和事件的区别
在"实现观察者模式(Observer Pattern)的2种方式"中,曾经通过接口的方式.委托与事件的方式实现过观察者模式.本篇体验使用Action实现此模式,并从中体验委托与事件 ...
- 委托、Lambda表达式、事件系列05,Action委托与闭包
来看使用Action委托的一个实例: static void Main(string[] args) { int i = 0; Action a = () => i++; a(); a(); C ...
- 委托、Lambda表达式、事件系列03,从委托到Lamda表达式
在"委托.Lambda表达式.事件系列02,什么时候该用委托"一文中,使用委托让代码简洁了不少. namespace ConsoleApplication2 { internal ...
- 委托、Lambda表达式、事件系列02,什么时候该用委托
假设要找出整型集合中小于5的数. static void Main(string[] args) { IEnumerable<int> source = new List<int&g ...
- 委托、Lambda表达式、事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性
委托是一个类. namespace ConsoleApplication1 { internal delegate void MyDelegate(int val); class Program { ...
- Kotlin枚举与委托深入详解
枚举: 基本上跟Java的差不多,这里就过一遍既可,如下: 还可以接收参数,如下: 枚举还可以定义方法,如下: 看下错误提示: 所以可以这样: 然后咱们再冒号之前定义对象,如下: 下面来使用一下: 当 ...
随机推荐
- 『无为则无心』Python基础 — 12、Python运算符详细介绍
目录 1.表达式介绍 2.运算符 (1)运算符的分类 (2)算数运算符 (3)赋值运算符 (4)复合赋值运算符 (5)比较运算符 3.逻辑运算符 拓展1:数字之间的逻辑运算 拓展2:Python中逻辑 ...
- ps 合并两张图片
1.ps 打开第一张图片,2.打开另一张图片为图层.3.选中图层,创建蒙版: 4.点击蒙版+按Alt键,打开蒙版:5.打开蒙版后选中渐变工具,途中黑色为不显示区域,(注意渐变模式要改为正常):6.调整 ...
- 配置tomcat虚拟主机
实例说明 本实例介绍如何配置tomcat的虚拟主机. 关键技术 关于server.xml中host这个元素,只有在设置虚拟主机是才会修改.虚拟主机是一种在一个Web服务器上服务多个域名的机制,对这个域 ...
- 初入web前端---实习(职场菜鹏)
作为一个大四的准职场新人,顺利的找到了一份自己想从事的工作---web前端开发.
- SpringBoot | 1.1 SpringBoot简介
前言 本博客仅为记录与总结SpringBoot的学习笔记,资料来源: 书籍<深入浅出SpringBoot>第三版 B站尚硅谷<雷丰阳2021版SpringBoot2零基础入门> ...
- SpringCloud:SpringBoot整合SpringCloud项目
划分模块 这里我划分了四个模块 Common: 存放bean和Dao模块 Consumer: 消费者模块,提供对外暴露接口服务 EurekaServer: Eureka注册中心模块,主要用于启动注册中 ...
- 《PHP设计模式大全》系列分享专栏
<PHP设计模式大全>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/read/201739.html 文章 php设计模式介绍之编程惯用法第 ...
- VMware中的虚机如何挂载U盘
1.将U盘插入到宿主机上. 2.在VM Client上,点击宿主机,右键,扫描存储设备(目的是为了发现新USB存储) 3.在需要的虚拟机上编辑配置,添加硬件,添加USB设备(如果不进行以上2个步骤,此 ...
- HTTP工作过程(浏览器输入URL到返回HTML页面都经历了什么)
超文本传送协议(HyperText Transport Protocol,HTTP)是互联网上应用最为广泛的一种网络协议,它工作在应用层,使用TCP的80号端口提供服务.并且HTTP是工作在客户/服务 ...
- PXE高效批量网络装机
PXE高效批量网络装机 一.PXE概述 1)PXE (Preboot eXcution Environment) ...