C#委托与匿名委托详解

作者:DW039 时间:2023-02-24 21:12:41 

本来是想写一篇《委托与lambda表达式的前世今生》,但仅委托部分已经写了很多内容,于是就此分开关于Lambda表达是的内容后续再写吧。

不知道Lambda表达式是谁发明的,只记得第一次接触Lambda表达式是在使用VS2008的时候,那就先认为是微软发明的吧。

Lambda表达式从我接触开始到现在变得越来越流行,Java8中开始支持、kotlin更是对C#,F#做了广泛的抄袭(C#曾几何时不也如此对待过Java嘛)。其实这都充分说明了,Lambda表达式的重要性。要搞清楚Lambda首先需要搞清楚委托。

委托:

假设现在我们要开发一个处理两个整数的程序(假设先处理相加操作)


public class Worker
   {
     /// <summary>
     /// 处理两个数
     /// </summary>
     /// <param name="a"></param>
     /// <param name="b"></param>
     /// <returns></returns>
     public int HandleTwoNumber(int a,int b)
     {
       return a + b;
     }
   }
static void Main(string[] args)
   {
     int a = int.Parse(Console.ReadLine());
     int b = int.Parse(Console.ReadLine());

Worker worker = new Worker();
     int result = worker.HandleTwoNumber(a, b);
     Console.WriteLine(String.Format("Result:{0}", result));

string p = Console.ReadLine();
}

如果一段时间后,我们需要它变更为减操作:


public class Worker
   {
     public int HandleTwoNumber(int a,int b)
     {
       return a - b;
     }
   }

虽然有a+b变为a-b的变化很微小,但后续此处可能面临多次变化(由减变为除.........)。有变化就应封装变化,此处我们可以将a与b的操作行为抽象出来,用什么抽象呢?委托


public class Worker
   {
     public delegate int TwoNumberHandleMethodDelegate(int x, int y);
     public int HandleTwoNumber(int a,int b)
     {
       return a + b;
     }
   }

public delegate int TwoNumberHandleMethodDelegate(int x, int y);此处用delegate标注,表明这是一个委托定义。如果去掉 delegate 再来观察该定义,你会发现这就是一个没有方法体的抽象方法。所以委托的含义即:与该抽象方法签名形式相同的方法的类型。委托就是一种你定义的新数据类型,它与int、class是一样的都是数据类型。int表示整数,只要是整数都可以赋值给 int型变量;TwoNumberHandleMethodDelegate则表示,接收两个int型参数并返回int型结果的这类方法,因此满足上述要求的方法都可赋值给TwoNumberHandleMethodDelegate类型的变量。

如此一来Worker代码可修改为:


public class Worker
   {
     public delegate int TwoNumberHandleMethodDelegate(int x, int y);
     public int HandleTwoNumber(int a, int b, TwoNumberHandleMethodDelegate handle)
     {
       return handle(a, b);
     }
   }

如此a、b的操作被封装起来,所有的变化均交由调用者来处理。此处的含义:HandleTwoNumber处理a、b两个整数,具体如何处理由 handle 实施。此时你可能会问,那如何来调用该方法呢?调用如下:


private static int Add(int a, int b)
   {
     return a + b;
   }

private static int Sub(int a, int b)
   {
     return a - b;
   }

static void Main(string[] args)
   {
     int a = int.Parse(Console.ReadLine());
     int b = int.Parse(Console.ReadLine());
     Worker.TwoNumberHandleMethodDelegate method = new Worker.TwoNumberHandleMethodDelegate(Add);
     Worker worker = new Worker();
     int result = worker.HandleTwoNumber(10, 10,method);
//int result = worker.HandleTwoNumber(10, 10, Sub);//简化版
     Console.WriteLine(String.Format("Result:{0}", result));
}

根据上面的程序可知,Main代码块为worker的调用者,作为调用者而言应该最清楚自己想要让woker做的工作。因此作为被调用者的worker而言,它只需要接收调用者Main给的a\b参数及执行Main定制的算法method,然后按照算法执行并返回结果即可。上面代码虽然简单,但其中的意义深远,随着编程时间的增加相信你的理解将越深刻。

委托变量在进行赋值时除了标准的方式,还可以进行简化:


Worker.TwoNumberHandleMethodDelegate method = new Worker.TwoNumberHandleMethodDelegate(Add);
     Worker worker = new Worker();
     int result = worker.HandleTwoNumber(10, 10,method);
//可简化为
// int result = worker.HandleTwoNumber(10, 10,Add);

编译器将自动检查Add是否符合 TwoNumberHandleMethodDelegate 的定义,如果符合允许直接将方法名赋值给委托变量。

匿名委托

通过上面的示例代码,我们很容易发现 TwoNumberHandleMethodDelegate method 变量被赋值为Add(Sub),因此在调用method(...)时相当于调用Add(.....)。这样一来就可以认为

method与Add完全等效,既然等效那是否可以直接将Add的定义内容赋值给method变量呢?答案是肯定的:


static void Main(string[] args)
   {

Worker.TwoNumberHandleMethodDelegate method =private static int Add(int a, int b)
   {
     return a + b;
   };
}

但像上面这种生拉硬套是不行的,你还需要做修改。修改内容是:因为现在的代码处于Main方法中,访问修饰符去掉,同样static也应去掉;同时编译器知道你要给method赋值,那么要赋的这个值肯定满足返回类型为int的要求,所有int在此时就多余了去掉;因为赋值之后method就等效于Add,以后调用只要通过method变量就可完成,所有Add方法名不需要去掉。如此代码变为如下形式:


static void Main(string[] args)
   {

Worker.TwoNumberHandleMethodDelegate method =  (int a, int b)
   {
     return a + b;
   };
}

经过上面的修改内容简化了很多,但method赋值的=右端是什么东西呢?此时编译器并不能正确识别这是一个方法,因为方法的定义需要满足包含:访问修身符、返回类型、方法名、参数列表、方法体五部分内容。虽然你心里清楚这是个简化了的方法,但是编译器不懂你的心.........,那没关系只要我们告诉编译器,后面的是个简化方法就可以了。


static void Main(string[] args)
   {

Worker.TwoNumberHandleMethodDelegate method =  delegate(int a, int b)
   {
     return a + b;
   };
}

正如你所期望的那样,现在编译器已经知道了=右侧是你经过简化的方法;ok,现在可以正常赋值并使用了。

通过上面的定义我们发现,用delegate标注的简化方法没有一个像Add/Sub一样固定的名字。因此我们称这种方法叫匿名委托(我习惯称匿名方法)。

你可能还注意到该匿名委托定义完毕后就赋值给Main代码快中的局部变量method,因此当超出method的作用域后,该方法就再也没有机会调用了。这引出了匿名方法、匿名委托、匿名函数它们的最常见用法,即用来定义只需要使用一次的功能代码。

来源:http://www.cnblogs.com/dw039/p/7417733.html

标签:C#,委托,匿名委托
0
投稿

猜你喜欢

  • elasticsearch索引index之engine读写控制结构实现

    2021-12-22 00:08:07
  • java多次嵌套循环查询数据库导致代码中数据处理慢的解决

    2023-10-28 22:17:50
  • Maven将代码及依赖打成一个Jar包的方式详解(最新推荐)

    2022-03-31 06:52:47
  • HashMap工作原理_动力节点Java学院整理

    2023-06-20 20:33:15
  • Mybatis-Plus之ID自动增长的设置实现

    2022-10-27 00:09:47
  • 如何基于LoadingCache实现Java本地缓存

    2023-04-02 00:14:55
  • C#利用FileSystemWatcher实时监控文件的增加,修改,重命名和删除

    2021-08-21 05:46:28
  • Java使用ThreadLocal实现当前登录信息的存取功能

    2023-06-06 12:00:34
  • SpringCloud Eureka的使用教程

    2022-03-23 22:30:59
  • Java实现多任务执行助手

    2023-05-17 14:15:30
  • 分析Java中为什么String不可变

    2023-06-05 23:33:25
  • Java实现简单酒店管理系统

    2023-02-22 12:41:21
  • 基于Java Socket实现一个简易在线聊天功能(一)

    2023-09-23 17:18:35
  • spring Boot查询数据分页显示的方法实例

    2023-04-28 13:30:08
  • AQS同步组件Semaphore信号量案例剖析

    2023-11-27 14:27:04
  • C#如何自动识别文件的编码

    2022-10-08 01:41:43
  • Android WorkManager使用以及源码分析

    2022-02-04 01:10:26
  • C#使用DevExpress中的XtraCharts控件实现图表

    2022-12-21 10:14:10
  • 使用Java设置字型和颜色的方法详解

    2023-04-14 05:09:23
  • SpringBoot使用注解进行分页的实现示例

    2021-08-21 22:45:32
  • asp之家 软件编程 m.aspxhome.com