C# - 多播委托 125
C# - 多播委托 125
C#多播委托(委托链)是一种特殊的委托类型,特殊在可以将多个相同签名的方法绑定到同一个委托实例上,调用委托实例时会一次性触发所有绑定的方法
多播委托使用特殊的加法和减法运算符来进行方法绑定和解绑操作;使用加法运算符(+=)将一个方法绑定到委托实例上,使用减法运算符(-=)将一个方法从委托实例上解绑;当调用委托实例时,所有绑定的方法都将被调用
using System;
namespace _5多播委托
{
//实例类
public class MyClass
{
//相同签名的实例方法
public void M1()
{
Console.WriteLine("M1");
}
public void M2()
{
Console.WriteLine("M2");
}
public void M3()
{
Console.WriteLine("M3");
}
public void M4()
{
Console.WriteLine("M4");
}
public void M5()
{
Console.WriteLine("M5");
}
}
//定义无返回值委托
public delegate void MyDelegate();
public class Program
{
public static void Main(string[] args)
{
MyClass mc = new MyClass();
//为委托赋值实例方法
MyDelegate md = mc.M1;
//使用+=将其他方法添加进md的委托组中
md += mc.M2;
md += mc.M3;
md += mc.M4;
md += mc.M5;
//调用委托实例,使用方法都会执行
md();
Console.WriteLine("========================");
//使用-=将M4从委托组中移除
md -= mc.M4;
//再次调用委托实例时只会执行
//除 M4以外的其他方法
md();
Console.ReadKey();
}
}
}
使用多播委托的注意事项:
1)调用委托时执行方法顺序与添加方法时的顺序一样,但是不能依赖与此顺序(主要是其底层机制并没有保证一定都是这个顺序,如果其底层机制发生改变,就会变成潜在的bug)
2)如果添加多个方法时使用的是 = 而不是 += ,就会覆盖掉之前添加的方法,只执行从 = 开始之后的所有+=方法,如之后还有 = 就会覆盖之前所有 =与+= 的方法,之后的不受影响
总之一句话,只要多播委托中出现等号,就会覆盖之前所有的=,+=与-=方法
MyDelegate md = mc.M1;
//使用+=将其他方法添加进md的委托组中
md += mc.M2;
//如果最后一个还是+=
//即md =+ mc.M5;
//就会执行M3-M5方法
//M1,M2方法会被 M3覆盖掉
md = mc.M3;
md += mc.M4;
//会覆盖掉之前所有的方法
//只执行M5
md = mc.M5;
//如果M5后面只有+=,如+=M6;+=M7;
//其执行结果为 M5-M7方法输出结果
//调用委托实例,使用方法都会执行
md();
//类似一个变量被多次赋值
//变量值保存最后一次的赋值结果
3)如果多播委托都有返回值,只会返回委托中最后添加方法的返回值,如果想要多播委托中每个方法的返回值,需要通过循环遍历,调用委托中的每个方法,实现获取每个方法的返回值
通过委托实例的调用GetInvocationList()方法,返回当前委托中的所有的方法,返回值类型是一个Delegate数组(委托数组)
通过反编译工具查看:所有的委托都继承自抽象类MulticastDelegate,而MulticastDelegate又继承自Delegate类(abstract也是抽象类)
多播委托内部就是将绑定在当前委托对象上的每个方法,又转换为一个委托对象,并且存储在了一个叫_invocationList的object 数组中,当调用委托时,其实就是循环遍历_invocationList数组,并且调用其中的每一个委托
//定义有返回值委托
public delegate int YouDelegate();
public class YouClass
{
public int M1()
{
return 1;
}
public int M2()
{
return 2;
}
public int M3()
{
return 3;
}
}
public class Program
{
public static void Main(string[] args)
{
YouClass yc=new YouClass();
YouDelegate yd1 = yc.M1;
yd1 += yc.M2;
yd1 += yc.M3;
//接收多播委托的返回值
int num1 = yd1();//3
Console.WriteLine("yd1={0}",num1);
Console.WriteLine("================");
YouDelegate yd2 = yc.M3;
yd2 += yc.M2;
yd2 += yc.M1;
//接收多播委托的返回值
int num2 = yd2();//1
Console.WriteLine("yd2={0}", num2);
Console.WriteLine("=====================");
YouDelegate yd3 = yc.M1;
yd3 += yc.M2;
yd3 += yc.M3;
//通过委托的GetInvocationList()方法得到委托数组
Delegate[] dgs = yd3.GetInvocationList();
foreach (var dgitem in dgs)
{
//将当前对象dgitem强制转换为
//自定义的委托类型YouDelegate
YouDelegate ydItem = (YouDelegate)dgitem;
//调用Invoke()方法,执行当前委托中的方法
int x = ydItem.Invoke();
Console.WriteLine("x={0}",x);
}
Console.ReadKey();
}
}
4)多播委托中的异常委托,从方法的异常地方往后以及之后的方法不再执行
public int M2()
{
throw new Exception("抛异常了,之后不再执行");
return 2;
}
5)委托的不可变性,与字符串的特性类似,主要表现在内存方面(了解即可)
昨天#山东##德州#突发#地震#,看#今日头条##短视频#有许多人发布收到#地震预警#信息的视频,通过预警信息得以提前撤离至安全地带,愿所有人平安无事,感谢国家地震预警系统的提醒减少人员伤亡事件