详解C#之委托

委托:顾名思义,让别人帮你办件事。委托是C#实现回调函数的一种机制。可能有人会问了,回调函数是个啥???

举个例子:我现在是一家公司的老板,公司现在在招聘.NET工程师,我们有一个小姐姐专门负责接受求职者投递的简历,我就告诉这个小姐姐,一旦收到新的简历就转发给我一份。

这个例子里小姐姐要做的工作:给我转发一份简历(回调函数里的操作),就是一个回调函数的作用。一旦有了满足条件(收到了新的简历),小姐姐就会转发给我(触发回调函数)

用来代码来看看是怎么实现的:

1.定义一个委托:

// 定义委托,这个委托需要获取一个int型参数,返回void
  internal delegate void Feedback(int value);

2.定义回调方法:

这里定义了两个方法,一个静态,一个实例。正好看看调用方式的不同。注意:定义的回调方法签名必须和委托对象一致(这里都是int 类型参数,没有返回值。这么说也不全对,涉及到协变和逆变。这里就不解释这俩了),这是因为将方法绑定到委托时,编译器会检测他们的兼容性。不符合的话回报编译错误。就比如有一个方法要传入String类型,我们给它传递了一个int类型一样。

这里为了方便演示就只把数字打印在了控制台。

/// <summary>
  /// 静态回调方法
  /// </summary>
  /// <param name="value"></param>
  private static void FeedbackToConsole(int value)
  {
   // 依次打印数字
   Console.WriteLine("Item=" + value);
  }
  /// <summary>
  /// 实例回调方法
  /// </summary>
  /// <param name="value"></param>
  private void InstanceFeedbackToConsole(int value)
  {
   Console.WriteLine("Item=" + value);
  }

3.编写一个方法来触发回调函数:

有三个参数:前两个做循环使用,后一个接收定义的委托对象。内部代码循环调用回调方法 fb(val)的写法,其实就是相当于要调用的函数。例:

FeedbackToConsole(val)

/// <summary>
  /// 使用此方法触发委托回调
  /// </summary>
  /// <param name="from">开始</param>
  /// <param name="to">结束</param>
  /// <param name="fb">委托引用</param>
  private static void Counter(int from,int to, Feedback fb)
  {
   for (int val = from; val <= to; val++)
   {
    // fb不为空,则调用回调方法
    if (fb != null)
    {
     fb(val);
    }
    //fb?.Invoke(val); 简化版本调用
   }
  }

4.定义Counter的方法调用(这一步可有可无,为了区分静态和实例方法就写了)

第一次调用Counter,传递Null,在回调方法里有一步判空操作,所以是不回调用回调函数的。第二个Counter调用正常传递参数,构造一个委托对象并绑定了一个方法

/// <summary>
  /// 静态调用
  /// </summary>
  private static void StaticDelegateDemo()
  {
   Console.WriteLine("---------委托调用静态方法------------");
   Counter(1, 10, null);
   Counter(1, 10, new Feedback(FeedbackToConsole));

  }

  /// <summary>
  /// 实例调用
  /// </summary>
  private static void InstanceDelegateDemo()
  {
   Console.WriteLine("---------委托调用实例方法------------");
   Program p = new Program();
   Counter(1, 10, null);
   Counter(1, 5, new Feedback(p.InstanceFeedbackToConsole));
  }

5. 查看控制台信息

完整代码:

class Program
 {
  // 定义委托,并引用一个方法,这个方法需要获取一个int型参数返回void
  internal delegate void Feedback(int value);
  static void Main(string[] args)
  {

   StaticDelegateDemo();
   InstanceDelegateDemo();
   Console.ReadKey();
  }

  /// <summary>
  /// 静态调用
  /// </summary>
  private static void StaticDelegateDemo()
  {
   Console.WriteLine("---------委托调用静态方法------------");
   Counter(1, 10, null);
   Counter(1, 10, new Feedback(FeedbackToConsole));

  }

  /// <summary>
  /// 实例调用
  /// </summary>
  private static void InstanceDelegateDemo()
  {
   Console.WriteLine("---------委托调用实例方法------------");
   Program p = new Program();
   Counter(1, 10, null);
   Counter(1, 5, new Feedback(p.InstanceFeedbackToConsole));
  }

  /// <summary>
  /// 静态回调方法
  /// </summary>
  /// <param name="value"></param>
  private static void FeedbackToConsole(int value)
  {
   // 依次打印数字
   Console.WriteLine("Item=" + value);
  }
  /// <summary>
  /// 实例回调方法
  /// </summary>
  /// <param name="value"></param>
  private void InstanceFeedbackToConsole(int value)
  {
   Console.WriteLine("Item=" + value);
  }
 }

启动控制台:可以看到已经成功把数字打印出来了

6. 委托链:

委托链是委托对象的集合。可以利用委托链调用集合中的委托所绑定的全部方法。继续在原有的基础上添加委托链的方法。

新添加的两个方法本质上没有区别都是对委托链的实现,不同的是写法,明显是第二个方法更加精简一些。这是因为C#编译器重载了+=和-=操作符,这两个操作符分别调用Combine和Remove。

/// <summary>
  /// 委托链调用 1
  /// </summary>
  /// <param name="p"></param>
  private static void ChainDelegateDemo(Program p)
  {
   Console.WriteLine("---------委托链调用1------------");
   Feedback fb1 = new Feedback(FeedbackToConsole);
   Feedback fb2 = new Feedback(p.InstanceFeedbackToConsole);
   Feedback fbChain = null;
   fbChain = (Feedback)Delegate.Combine(fbChain, fb1);
   fbChain = (Feedback)Delegate.Combine(fbChain, fb2);
   Counter(1, 3, fbChain);
   Console.WriteLine();
   fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToConsole));
   Counter(1, 3, fbChain);
  }

  /// <summary>
  /// 委托链调用 2
  /// </summary>
  /// <param name="p"></param>
  private static void ChainDelegateDemo2(Program p)
  {
   Console.WriteLine("---------委托链调用2------------");
   Feedback fb1 = new Feedback(FeedbackToConsole);
   Feedback fb2 = new Feedback(p.InstanceFeedbackToConsole);
   Feedback fbChain = null;
   fbChain += fb1;
   fbChain += fb2;
   Counter(1, 3, fbChain);
   Console.WriteLine();
   fbChain -= new Feedback(FeedbackToConsole);
   Counter(1, 2, fbChain);
  }

在Main方法添加对委托链的调用:

static void Main(string[] args)
  {
   Program p = new Program();
   StaticDelegateDemo();
   InstanceDelegateDemo();
   ChainDelegateDemo(p);
   ChainDelegateDemo2(p);
   Console.WriteLine("Hello World!");
   Console.ReadKey();
  }

启动项目:

7. C#为委托提供的简化:

7.1 不需要构造委托对象:

之前的代码:

Counter(1, 10, new Feedback(FeedbackToConsole));

构造了一个委托对象并传递给Counter方法,由于C#编译器能自己推断。所以可以省略构造委托对象,直接传递方法。使代码的可读性更佳,也更容易理解。

简化后的代码:

/// <summary>
  /// 静态调用
  /// </summary>
  private static void StaticDelegateDemo()
  {
   Console.WriteLine("---------委托调用静态方法------------");
   Counter(1, 10, null);
   //Counter(1, 10, new Feedback(FeedbackToConsole));
   Counter(1, 10, FeedbackToConsole);

  }

可以看到效果是一样的:

7.2 简化语法:不需要定义回调方法(以lambda表达式实现)

在前面的代码中定义了一个回调方法:

/// <summary>
  /// 静态回调方法
  /// </summary>
  /// <param name="value"></param>
  private static void FeedbackToConsole(int value)
  {
   // 依次打印数字
   Console.WriteLine("Item=" + value);
  }

现在以lambda表达式方式实现:

/// <summary>
  /// 静态调用
  /// </summary>
  private static void StaticDelegateDemo()
  {
   Console.WriteLine("---------委托调用静态方法------------");
   Counter(1, 10, null);
   //Counter(1, 10, new Feedback(FeedbackToConsole));
   //Counter(1, 10, FeedbackToConsole);
   Counter(1, 10, value => Console.WriteLine(value));

  }

lambda表达式实际上是一个匿名函数。编译器在看到lambda之后会在类中自动定义一个新的私有方法。类似于之前写的回调方法FeedbackToConsole()lambda必须匹配委托!

lambda的语法: 参数 => 方法体。

=>左边是要传入的参数,本例中是传入一个Int类型的变量,=>右边是具体的代码,相当于FeedbackToConsole(),{}中所做的操作

一些规则:

如果不传递参数: ()=>Console.WriteLine("Hello World!")

传递一个参数:(int n)=>Console.WriteLine(n.ToString())    或者去掉()和int  编译器会自己推断类型:n=>Console.WriteLine(n.ToString())

传递多个参数:(int n ,int m)=>Console.WriteLine(n.ToString())  或者编译器自己推断类型:(n , m)=>Console.WriteLine(n.ToString())

注:如果有一个方法需要多处调用或者方法里面的代码量较多。还是单独写一个方法较为理想。

最后看一下换成lambda的写法结果显示是否一样

全部代码:

class Program
 {
  // 定义委托,并引用一个方法,这个方法需要获取一个int型参数返回void
  internal delegate void Feedback(int value);
  static void Main(string[] args)
  {
   Program p = new Program();
   StaticDelegateDemo();
   InstanceDelegateDemo();
   ChainDelegateDemo(p);
   ChainDelegateDemo2(p);
   Console.WriteLine("Hello World!");
   string[] names = { "Jeff", "Jee", "aa", "bb" };
   //char find = 'e';
   //names= Array.FindAll(names, name => name.IndexOf(find) >= 0);
   //Array.ForEach(names, Console.WriteLine);
   Console.ReadKey();
  }

  /// <summary>
  /// 静态调用
  /// </summary>
  private static void StaticDelegateDemo()
  {
   Console.WriteLine("---------委托调用静态方法------------");
   Counter(1, 10, null);
   //Counter(1, 10, new Feedback(FeedbackToConsole));
   //Counter(1, 10, FeedbackToConsole);
   Counter(1, 10, value => Console.WriteLine(value));

  }

  /// <summary>
  /// 实例调用
  /// </summary>
  private static void InstanceDelegateDemo()
  {
   Console.WriteLine("---------委托调用实例方法------------");
   Program p = new Program();
   Counter(1, 10, null);
   Counter(1, 5, new Feedback(p.InstanceFeedbackToConsole));
  }

  /// <summary>
  /// 委托链调用 1
  /// </summary>
  /// <param name="p"></param>
  private static void ChainDelegateDemo(Program p)
  {
   Console.WriteLine("---------委托链调用1------------");
   Feedback fb1 = new Feedback(FeedbackToConsole);
   Feedback fb2 = new Feedback(p.InstanceFeedbackToConsole);
   Feedback fbChain = null;
   fbChain = (Feedback)Delegate.Combine(fbChain, fb1);
   fbChain = (Feedback)Delegate.Combine(fbChain, fb2);
   Counter(1, 3, fbChain);
   Console.WriteLine();
   fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToConsole));
   Counter(1, 3, fbChain);
  }

  /// <summary>
  /// 委托链调用 2
  /// </summary>
  /// <param name="p"></param>
  private static void ChainDelegateDemo2(Program p)
  {
   Console.WriteLine("---------委托链调用2------------");
   Feedback fb1 = new Feedback(FeedbackToConsole);
   Feedback fb2 = new Feedback(p.InstanceFeedbackToConsole);
   Feedback fbChain = null;
   fbChain += fb1;
   fbChain += fb2;
   Counter(1, 3, fbChain);
   Console.WriteLine();
   fbChain -= new Feedback(FeedbackToConsole);
   Counter(1, 2, fbChain);
  }
  /// <summary>
  /// 使用此方法触发委托回调
  /// </summary>
  /// <param name="from">开始</param>
  /// <param name="to">结束</param>
  /// <param name="fb">委托引用</param>
  private static void Counter(int from,int to, Feedback fb)
  {
   for (int val = from; val <= to; val++)
   {
    // fb不为空,则调用回调方法
    if (fb != null)
    {
     fb(val);
    }
    //fb?.Invoke(val); 简化版本调用
   }
  }

  /// <summary>
  /// 静态回调方法
  /// </summary>
  /// <param name="value"></param>
  private static void FeedbackToConsole(int value)
  {
   // 依次打印数字
   Console.WriteLine("Item=" + value);
  }
  /// <summary>
  /// 实例回调方法
  /// </summary>
  /// <param name="value"></param>
  private void InstanceFeedbackToConsole(int value)
  {
   Console.WriteLine("Item=" + value);
  }
 }

以上就是详解C#之委托的详细内容,更多关于C#之委托的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解C#中的委托

    委托这个东西不是很好理解,可是工作中又经常用到,你随处可以看到它的身影,真让人有一种又爱又恨的感觉,我相信许多人被它所困扰过. 一提到委托,如果你学过C语言,你一定会马上联想到函数指针. 什么是委托?委托是C#中类型安全的,可以订阅一个或多个具有相同签名方法的函数指针.委托可以把函数做为参数传递,其实际意义便是让别人代理你的事情.委托可以看做是函数的指针,整数可以用整数变量指向它,对象可以用对象变量指向它, 函数也可以用委托变量指向它.我们可以选择将委托类型看做只定义了一个方法的接口,而委托的实

  • 详解C#中通过委托来实现回调函数功能的方法

    委托(delegate)是一种可以把引用存储为函数的类型,这类似于c++中的函数指针. 回调函数 c++中的回调函数,就是用函数指针来实现的.类似的,c#中用委托,来实现回调函数的功能. 回调函数为什么被称为回调函数?比如你调用了一个函数,那么就叫调用,但是如果你在调用一个函数的时候,还需要把一个函数提供给该函数,让这个函数来调用你的函数,那么你提供的这个函数就被称为回调函数(callback). 对于python这样的动态语言而言,就没有c#,c++提供特殊的语法实现回调函数,因为在pytho

  • c# 委托详解

    委托是一个类型.C#中的委托是面向对象的,并且它是类型安全的 当创建委托实例的时候,创建的实例会包含一个调用列表,在调用列表中可以包含多个方法.每个方法称作一个调用实体.调用实体可以是静态方法,也可以是实例方法.如果是实例方法,则该调用实体包含调用该实例方法的实例.委托并不关心它所调用方法所属的类,它只关心被调用方法与委托的类型是否兼容. 下面是代码实例: using System; namespace LycheeTest{ public delegate void D(int a, int

  • C#用委托BeginInvoke做异步线程

    一个应用场景,浏览器上传一个文件,此文件后台调用文件转换,需要耗费相当长的时间,这样,如果是一个线程同步式的做下去,那么用户在浏览器上感觉就是卡住了,卡卡卡卡,这里我们利用委托的BeginInvoke和EndInvoke方法操作线程,BeginInvoke方法可以使用线程异步地执行委托所指向的方法.然后通过EndInvoke方法获得方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值),或是确定方法已经被成功调用,说白了就是相当于开个多线程,你用户文件保存了之后,响应返回,这个Be

  • C#委托与匿名委托详解

    本来是想写一篇<委托与lambda表达式的前世今生>,但仅委托部分已经写了很多内容,于是就此分开关于Lambda表达是的内容后续再写吧. 不知道Lambda表达式是谁发明的,只记得第一次接触Lambda表达式是在使用VS2008的时候,那就先认为是微软发明的吧. Lambda表达式从我接触开始到现在变得越来越流行,Java8中开始支持.kotlin更是对C#,F#做了广泛的抄袭(C#曾几何时不也如此对待过Java嘛).其实这都充分说明了,Lambda表达式的重要性.要搞清楚Lambda首先需要

  • C#中委托(Delegates)的使用方法详解

    1. 委托是什么? 其实,我一直思考如何讲解委托,才能把委托说得更透彻.说实话,每个人都委托都有不同的见解,因为看问题的角度不同.个人认为,可以从以下2点来理解: (1) 从数据结构来讲,委托是和类一样是一种用户自定义类型. (2) 从设计模式来讲,委托(类)提供了方法(对象)的抽象. 既然委托是一种类型,那么它存储的是什么数据? 我们知道,委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址.调用委托的时候,委托包含的所有方法将被执行. 2. 委托类型的定义 委托是类型,就

  • 详解C#之委托

    委托:顾名思义,让别人帮你办件事.委托是C#实现回调函数的一种机制.可能有人会问了,回调函数是个啥??? 举个例子:我现在是一家公司的老板,公司现在在招聘.NET工程师,我们有一个小姐姐专门负责接受求职者投递的简历,我就告诉这个小姐姐,一旦收到新的简历就转发给我一份. 这个例子里小姐姐要做的工作:给我转发一份简历(回调函数里的操作),就是一个回调函数的作用.一旦有了满足条件(收到了新的简历),小姐姐就会转发给我(触发回调函数) 用来代码来看看是怎么实现的: 1.定义一个委托: // 定义委托,这

  • 详解C#中委托,事件与回调函数讲解

    .Net编程中最经常用的元素,事件必然是其中之一.无论在ASP.NET还是WINFrom开发中,窗体加载(Load),绘制(Paint),初始化(Init)等等. "protected void Page_Load(object sender, EventArgs e)"这段代码相信没有人不熟悉的.细心一点一定会发现,非常多的事件方法都是带了"object sender, EventArgs e"这两个参数.这是不是和委托非常相似呢? 一.委托(有些书中也称为委派)

  • C#事件(event)使用方法详解

    事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂.而这些东西却往往又是编程中常用且非常重要的东西.大家都知道windows消息处理机制的重要,其实C#事件就是基于windows消息处理机制的,只是封装的更好,让开发者无须知道底层的消息处理机制,就可以开发出强大的基于事件的应用程序来. 先来看看事件编程有哪些好处. 在以往我们编写这类程序中,往往采用等待机制,为了等待某件事情的发生,需要不断地检测某些判断变量,而引入事件编程后,大大简化了这种过程: - 使用事件,可以很方

  • java实现事件委托模式的实例详解

    java实现事件委托模式的实例详解 举例说明: 一个班级,有两类学生,A类:不学习,玩,但是玩的东西不一样,有的是做游戏,与的是看电视(有点不合理) B类:放哨的学生,专门看老师的动向,如果老师进班了就立即通知大家. 如此就形成了一个需求,放哨的学生要通知所有玩的学生:老师来了,而不同的学生有不同的反应,有的马上把电视关闭,有的停止玩游戏. 设计的要求如下,让A类学生和B类学生完全解耦,即A类完全不知道B类的学生,却可以通知B类的学生. 代码及说明如下: Event 类,定义了一个事件类: pa

  • 详解c# 委托链

    引言: 上一专题介绍了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的介绍都是委托只是封装一个方法,那委托能不能封装多个方法呢?因为生活中经常会听到,我代表大家的意见等这样的说话,既然委托也是一个代表,那他如果只能代表一个人,那他的魅力就不是很大了吧,所以我们就会委托能不能代表多个方法的? 答案是可以的,这就是本专题要讲的内容--委托链,委托链也是一个委托,只是因为它是把多个委托链在一起,所以我们就以委托链来这么称呼它的. 一.到底什么是委托链

  • js事件委托详解

    1.每个函数都是对象,占用内存.内存中的对象越多,性能越差.解决事件处理过多问题的办法是事件委托. 2.事件委托冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件. 实例 <ul id="myLinks"> <li id="myLi1">text1</li> <li id="myLi2">text2</li> <li id="myLi3">text

  • JavaScript中事件委托的示例详解

    目录 事件流 事件委托 结尾 大家好,我是前端西瓜哥.今天我们来认识一下事件委托. 所谓事件委托,就是将原本应该在当前元素绑定的事件,放到它的祖先元素上,让祖先元素来委托处理. 事件流 事件流指从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序. 事件流由两阶段组成: 捕获事件 冒泡事件 我们通常用 addEventListener 给元素添加事件: document.querySelector('#card')addEventListener( 'click', function (ev

  • C#中委托和事件的区别详解

    目录 委托和事件的概念 委托和事件的作用 委托和事件的区别 委托和事件代码实践 总结 委托和事件的概念 委托 C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针.委托(Delegate) 是存有对某个方法的引用的一种引用类型变量.引用可在运行时被改变.它本质上也是一个类. 它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法. 事件 事件由对象引发,通过我们提供的代码来处理.一个事件我们必须订阅(Subscribe)他们,订阅一个事

  • Android开发之Kotlin委托的原理与使用详解

    目录 前言 一.接口/类委托 二.属性委托 三.延迟委托 四.观察者委托 五.Map委托 总结 前言 在设计模式中,委托模式(Delegate Pattern)与代理模式都是我们常用的设计模式(Proxy Pattern),两者非常的相似,又有细小的区分. 委托模式中,委托对象和被委托对象都是同一类型的对象,委托对象将任务委托给被委托对象来完成.委托模式可以用于实现事件监听器.回调函数等功能. 代理模式中,代理对象与被代理对象是两种不同的对象,代理对象代表被代理对象的功能,代理对象可以控制客户对

  • iOS UITableView 与 UITableViewController实例详解

    很多应用都会在界面中使用某种列表控件:用户可以选中.删除或重新排列列表中的项目.这些控件其实都是UITableView 对象,可以用来显示一组对象,例如,用户地址薄中的一组人名. UITableView 对象虽然只能显示一行数据,但是没有行数限制. •编写新的应用程序 JXHomepwner 应用 创建应用,填写基本信息 •UITableViewController UITableView 是视图.我们知道 模型-视图-控制器(Model-View-Controller),他是我们必须遵守的一种

随机推荐