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);
GetInvocationList()
复制代码

 

posted @   羊行天下  阅读(411)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示