• .NET 回调、接口回调、 委托


    回调浅析(委托、接口回调)
    说到C#回调,通常情况下,指的是某个委托或者接口回调。现将从网上各位前辈那里学得的一些经验加以整理,形成一个稍全面一些的文章,希望对大家有所帮助!
    一、 委托
    先看一段代码:
    // 定义委托
    delegate void WorkDone();

    class Program
    {
    static void Main(string[] args)
    {
    Do();

    	Console.ReadLine();
    }
    
    public static void Do()
    {
    	// 首先给callback委托赋值
    	WorkDone callback = new WorkDone(WorkDoneHandler);
    	 //WorkDone callback = WorkDoneHandler;   等价  简写
    	
    	// 将callback作为参数
    	Working(callback);
    }
    
    public static void Working(WorkDone callBack)
    {
    	// 当工作完成的时候执行这个委托
    	callBack();
    }
    
    public static void WorkDoneHandler()
    {
    	Console.WriteLine(DateTime.Now);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    }

    上面的代码中,将方法WorkDoneHandler()作为参数,传递给了另一个方法Working(WorkDone callBack),这样做的好处在于,可以动态的指定执行哪个方法。比如在Do()方法中,我们指定的callback 是WorkDoneHandler 当然也可以是其它匹配的方法。而Working()方法根本不需要知道自己最后执行的是哪个Handler。
    二、 接口回调
    通常情况下,我们创建一个对象,并马上直接去使用它的方法。然而,在有些情况下,希望能在某个场景出现后或条件满足时才调用此对象的方法。回调就可以解决这个“延迟调用对象方法”的问题。这个被调用方法的对象称为回调对象。
    实现回调的原理简介如下:
    首先创建一个回调对象,然后再创建一个控制器对象,将回调对象需要被调用的方法告诉控制器对象。控制器对象负责检查某个场景是否出现或某个条件是否满足。当此场景出现或此条件满足时,自动调用回调对象的方法。
    //----------------------------
    TestMulticastDelegate tmd = new TestMulticastDelegate (PrintMessage1);
    tmd += new TestMulticastDelegate (PrintMessage2);
    tmd +=new TestMulticastDelegate ( PrintMessage3);

    等价简写
    TestMulticastDelegate tmd = PrintMessage1;
    tmd += PrintMessage2;
    tmd +=PrintMessage3;

    最后,我们要用一种比较复杂的方法来写,但是却是链式委托的核心所在:
    
    • 1

    TestMulticastDelegate tmd1 = new TestMulticastDelegate(PrintMessage1);
    TestMulticastDelegate tmd2 = new TestMulticastDelegate(PrintMessage2);
    TestMulticastDelegate tmd3 = new TestMulticastDelegate(PrintMessage3);
    // 核心本质:将三个委托串联起来
    TestMulticastDelegate tmd = tmd1 + tmd2 + tmd3;
    tmd.Invoke(); // 显式调用Invoke方法来调用委托 同步的,beginInvoke异步
    tmd();// 隐式调用委托
    我们在实际开发中经常使用第二种方法,但是却不能不了解方法三,它是链式委托的本质所在。
    //---------------------------------
    以下为C#实现回调的一个小例子:
    using System;
    using System.Collections.Generic;
    using System.Text;
    namespace ConsoleApplication1
    {
    class Program
    {
    static void Main(string[] args)
    {
    //创建一个控制器对象,将提供给它的回调对象传入
    Controller obj = new Controller(new CallBack());
    //启动
    obj.Star();
    }
    }
    public interface IBack
    {
    void run();
    }
    public class CallBack : IBack
    {
    public void run()
    {
    //为了简洁这里只是显示下时间
    System.Console.WriteLine(DateTime.Now);
    }
    }
    public class Controller
    {
    public IBack CallBackObj = null; //这里引用回调对象
    public Controller(IBack obj)
    {
    this.CallBackObj = obj;
    }
    public void Star()
    {
    Console.WriteLine(“敲键盘任意键就显示当前的时间,直到按ESC退出…”);
    while (Console.ReadKey(true).Key != ConsoleKey.Escape)
    {
    CallBackObj.run();
    }
    }
    }
    }
    可以看到,当示例程序运行时,何时调用CallBack对象的run()方法是由用户决定的,用户每敲一个键,控制器对象就调用一次CallBack的run()方法。这个示例中实现回凋的关键在于IBack接口的引入。

     如果不用IBack接口,而直接使用 CallBack对象,一样可以实现同样的效果,如下: 
       public class Controller 
     { 
         public CallBack CallBackObj = null;   //回调对象方法的引用 
         public Controller(CallBack obj) 
         { 
             this.CallBackObj = obj; 
         } 
         public void Star() 
         { 
             Console.WriteLine("敲键盘任意键就显示当前的时间,直到按ESC退出...."); 
             while (Console.ReadKey(true).Key != ConsoleKey.Escape) 
             { 
                 CallBackObj.run(); 
             } 
         } 
     } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    但仔细思考,这样做的结果就使Controller类与CallBack对象绑定在一起,万一如果需要调用其他类型的对象,则必须修改Controller类的代码。
    如果Controller类接收的是一个抽象的接口变量Iback,则任何实现了该接口的对象都可以被Controller类对象所回调,Controller类的代码就再不用被修改,保证了代码对环境的适应性,无疑是一个很好的解决方案。

    在这里插入图片描述
    委托的方法既可以是无返回值的,也可以是有返回值的,但如果多一个带返回值的方法被添加到委托链中时,我们需要手动地调用委托链上的每个方法,否则只能得到委托链上最后被调用的方法的返回值。
    foreach (var del in 委托对象.GetInvocationList())
    {
    Console.WriteLine(del.DynamicInvoke());
    }
    在这里插入图片描述

  • 相关阅读:
    Scala继承
    一文看懂Mysql锁
    火遍全网的DPU,到底是个啥?
    Java-IO流之字节输入流(中篇)
    第1章 打造深度学习工具箱
    使用aqua data studio进行mysql、oracle、syabse等等debug调试
    202212 青少年等级考试机器人实操真题三级
    选 择 器
    猿创征文丨赶紧进来!!!轻松掌握C语言指针(进阶篇)
    libcurl库安装和使用
  • 原文地址:https://blog.csdn.net/u013400314/article/details/126626162