C# 带返回值多播/组播委托传递返回值的方法
委托是C#里非常强大的一个性质,众所周知强类型语言中一般不允许把函数作为对象传递,你不能像JS/TS里这样写:
1 function Arouse(doing : (arg0 : number)=> boolen ){ 2 for(let i = 0;i < array.length;i++){ 3 if(!doing(Some.value) break; //如果回调函数返回false则终止循环 4 } 5 }
C#中可以定义委托代替“JS函数参数里的函数”(也就是上面代码里的doing),实现将函数、方法作为参数传递:
1 /// <summary> 2 /// 四则运算委托 3 /// </summary> 4 /// <param name="left">左侧的数</param> 5 /// <param name="right">右侧的数</param> 6 /// <returns>运算结果</returns> 7 public delegate float FourOperations(float left,float right); 8 9 /// <summary> 10 /// 计算器 11 /// </summary> 12 /// <param name="left">左侧的数</param> 13 /// <param name="right">右侧的数</param> 14 /// <param name="calculators">计算用的方法/函数</param> 15 /// <returns>运算结果</returns> 16 public float Calculator(float left,float right,FourOperations calculators){ 17 return calculators.Invoke(left,right); 18 }
可以定义一个Sum方法,将两边数相加返回,然后将Sum方法传入Calculator()的第三个参数;
不过委托的真正力量在于多播/组播,也就是一口气执行多个方法:
1 public FourOperations Operations; //以定义的委托类型创建变量 2 3 Operations += Sum; //用+=操作符加入委托 4 Operations += Multiply; 5 6 public float Sum(float a,float b) => a+b; 7 public float Multiply(float a,float b) +=> a*b; 8 9 var r = Calculator(1,3,Operations); //将多播委托传入
此时会有一个问题,变量r的值实际上是1 * 3 = 3,1 + 3的结果被抛弃了,因为委托只会返回最后一个方法计算的值
为此,我们可以这么做:
1 public float Calculator(float initial,float right,FourOperations calculators){ 2 float chain = initial; 3 foreach(FourOperations fo in calculators.GetInvocationList()){ 4 chain = calculators.Invoke(chain,right); 5 } 6 }
chain意为链条,指的是返回值像链条一样传递;这次再执行Calculator(1,2,Operations)后,r的值就是(1 + 3) * 3 = 12。
当然,实际中不会像我举例的这样写计算器,如果是想要实现多个算式的话,结构体参数列表是更好的选择(而不是组播委托)。
例子展示了一种传递组播委托返回值的思路,其关键在于GetInvocationList()返回的 单个委托 数组。
(注意,在使用foreach遍历该数组时,不要使用var定义变量,这样会导致变量被认为是Delegate{}而不是你定义的委托)
(附上C#GetInvocationList()的元数据)

// // 摘要: // Returns the invocation list of this multicast delegate, in invocation order. // // 返回结果: // An array of delegates whose invocation lists collectively match the invocation // list of this instance. // // 异常: // T:System.MemberAccessException: // Cannot create an instance of an abstract class, or this member was invoked with // a late-binding mechanism. public sealed override Delegate[] GetInvocationList(); // // 摘要: // Populates a System.Runtime.Serialization.SerializationInfo object with all the // data needed to serialize this instance. // // 参数: // info: // An object that holds all the data needed to serialize or deserialize this instance. // // context: // (Reserved) The location where serialized data is stored and retrieved. // // 异常: // T:System.ArgumentNullException: // info is null. // // T:System.MemberAccessException: // Cannot create an instance of an abstract class, or this member was invoked with // a late-binding mechanism. // // T:System.Runtime.Serialization.SerializationException: // A serialization error occurred. public override void GetObjectData(SerializationInfo info, StreamingContext context);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?