C#基础(三十八)详细介绍委托、回调:一个类调用另一个类的方法

一、简介

        在基于Prism的MVVM架构中,用到了Socket通信作为Server。SocketClass类定义了单例模式,然后在软件启动的时候,就加载SocketClass并一直监听Client的消息。该消息包行了不同的标志,根据标志值加载不同类的方法。也就是加载View.xaml对应的ViewModel.cs。

       那么问题来了,如何加载其他类(ViewModel.cs)的方法呢?用委托就可以解决。

二、委托、回调知识(参考)

2.1、官网

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/using-delegates

2.2、CSND

委托:一个类调用另个类的方法。相当于调用一个方法体。

回调:用委托调用一个类的方法后,再返回该方法。相当于返回一个方法体。回调是从你的线程上开始执行的,回调即一个对象将一个方法的引用(方法的引用用委托保存)传入另一个对象,使得只有他能返回信息,这就是一个回调。

https://blog.csdn.net/falcomavin/article/details/72882939

https://blog.csdn.net/huang9012/article/details/38753305

https://www.cnblogs.com/kudsu/p/7722334.html(委托,重点)

https://www.jb51.net/article/98976.htm(委托+回调)

https://www.cnblogs.com/yangfengwu/p/5761841.html(委托+回调)

https://www.cnblogs.com/joy99/p/7354233.html

三、委托应用

主程序

#region 委托
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using test;

namespace QueueSample
{
    class Program
    {
        public delegate int MethodDelegate(int x, int y);
        public delegate int MyDel(int name);
        private static MethodDelegate method;
        static void Main(string[] args)
        {
            /*一、委托只调用一个静态方法*/
            Console.WriteLine("一、委托只调用一个静态方法");
            method = new MethodDelegate(DelegateClass.Add);
            int aa = method(10, 20);
            Console.WriteLine(method(10, 20));


            /*二、委托同时调用两个静态方法*/
            Console.WriteLine("二、委托同时调用两个静态方法");
            var add = new MyDel(DelegateClass.Add1);
            add += new MyDel(DelegateClass.Add2);//多播委托:委托重载Add2方法。相当于一个委托可以加载多个方法。
            add(10);
            //Console.WriteLine(add(10));

            Console.ReadLine();

        }

    }
}
#endregion

委托的方法 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace test
{
    public class DelegateMethon
    {
        static int a = 0;
        static int b = 0;
        public static int Add(int x, int y)
        {
            a = x;
            b = y;
            return x + y;
        }

        public static int Add1(int a)
        {
            var b = 10 + a;
            Console.WriteLine(b);
            return b;
        }
        public static int Add2(int a)
        {
            var b = 10 - a;
            Console.WriteLine(b);
            return b;
        }
    }
}

四、回调应用

4.1、举例一

请看上面博客链接。

https://www.cnblogs.com/kudsu/p/7722334.html(委托,重点)

https://www.jb51.net/article/98976.htm(委托+回调)

https://www.cnblogs.com/yangfengwu/p/5761841.html(委托+回调)

http://www.cnblogs.com/sunfom/p/8145066.html

参考下面的博客,写一个例子

https://blog.csdn.net/qq_36927190/article/details/79330171

#region 委托\回调
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using test;

namespace QueueSample
{
    class Program
    {
        public delegate int MethodDelegate(int x, int y);
        public delegate int MyDel(int name);
        private static MethodDelegate method;

        public delegate void MethodDelegateA(int x, int y);
        private static MethodDelegateA methodA;
        static void Main(string[] args)
        {
            /*一、委托只调用一个静态方法*/
            Console.WriteLine("一、委托只调用一个静态方法");
            method = new MethodDelegate(DelegateMethon.Add);
            int aa = method(10, 20);
            Console.WriteLine(method(10, 20));
            methodA = new MethodDelegateA(DelegateMethon.Add3);
            methodA(11, 99);

            /*二、委托同时调用两个静态方法*/
            Console.WriteLine("二、委托同时调用两个静态方法");
            var add = new MyDel(DelegateMethon.Add1);
            add += new MyDel(DelegateMethon.Add2);//多播委托:委托重载Add2方法。相当于一个委托可以加载多个方法。
            add(10);


            /*三、回调函数1:*/
            Console.WriteLine("三、回调函数1:");
            CallBackClasss c = new CallBackClasss();
            c.TestCallBack(PublicFunc.CallBack);
            Console.ReadLine();
        }    
    }
}
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace test
{
    public class CallBackClasss
    {
        public void TestCallBack(Action what)
        {
            Console.WriteLine("开始");
            Thread.Sleep(2000);
            what("233");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace test
{
    public class PublicFunc
    {
        public static void CallBack(string s)
        {
            Console.WriteLine(s);
            Console.ReadLine();
        }
    }
}

4.2、举例二

        参考别人的项目,用到了回调函数,一直不明白,现在把它解剖出来。

第一步:初始化

 public StudyPage()
        {
            InitializeComponent();
            m_cStudyEventProc.m_cKrayGenDll.SetDRUIUpdate(DRGenUpdateUIFun);
        }

DRGenUpdateUIFun是函数的SetDRUIUpdate实参,以后委托的指针就指向了DRGenUpdateUIFun实参了。 这步骤,我们先不讨论这个实现是什么东西。我我们先看函数SetDRUIUpdate()。

第二步:找出SetDRUIUpdate函数

 ///
        ///功能描述:设置DR回调更新UI功能函数
        ///参数:无
        ///返回值: 无
        ///
        public void SetDRUIUpdate(DRInfoDelegate ICallBack)
        {
            m_fDRUpdateUIInfo = ICallBack;
        }

       形参ICallBack,就是一个委托DRInfoDelegate。实际上,SetDRUIUpdate函数的参数,传递了一个委托进来。于是,我们需要找到这个DRInfoDelegate是什么东西?

第三步:找出DRInfoDelegate委托

   //UI更新委托函数
        public delegate void DRInfoDelegate(int nCmd, int nVal);
        private DRInfoDelegate m_fDRUpdateUIInfo = null;
    

 到了这里,你就会明白。DRInfoDelegate传入两个参数,返回值Void。此外,你不经要问,m_fDRUpdateUIInfo 明明等于null,我们到底在哪实例化这个委托对象m_fDRUpdateUIInfo呢?

第四步:找出DRInfoDelegate委托的对象m_fDRUpdateUIInfo到底在哪赋值了。

      你再仔细看看,m_fDRUpdateUIInfo在第一步的SetDRUIUpdate函数中,赋值了。绕来绕去,妈的,我现在重新理解一下SetDRUIUpdate这个函数。这个函数的功能就是,为委托变量m_fDRUpdateUIInfo赋值一个委托形参ICallBack。

         m_fDRUpdateUIInfo委托指向或者说调用 ICallBack委托。相当于连个委托指向同一个地址。

第五部: ICallBack委托参数,又指向了谁?这个是最重要的。

      指向了DRGenUpdateUIFun方法。

第六部:那么DRGenUpdateUIFun方法又是什么呢?

        ///
        ///功能描述: 通知更新功能函数
        ///参数:nCmd        消息命令
        ///     nVal        值
        ///返回值: 无
        ///
        private void DRGenUpdateUIFun(int nCmd, int nVal)
        {
            this.Dispatcher.Invoke(new GenUpdateDRDataDelegate(UpdateGenDRFunProc), new object[] { nCmd, nVal });
        }

DRGenUpdateUIFun方法,会执行GenUpdateDRDataDelegate这个委托下的UpdateGenDRFunProc方法。

GenUpdateDRDataDelegate委托:

 private delegate void GenUpdateDRDataDelegate(int Cmd, int Val);

UpdateGenDRFunProc方法:

        ///
        ///功能描述: 处理高压DR模式返回消息更新UI功能函数
        ///参数:nCmd        消息命令
        ///     nVal        值
        ///返回值: 无
        ///
        private void UpdateGenDRFunProc(int nCmd, int nVal)
        {
            double fMa;
            double fMs;
            double fMas;

            switch (nCmd)
            {
                case KrayGenDll.GEN_EM_MSG:         //摄影模式
                    SetEMValue(nVal);
                    break;
                case KrayGenDll.GEN_KV_MSG:         //普通摄影Kv值
                    m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- DR-KV=" + Convert.ToString(nVal));
                    m_cGlobalData.m_StudyDicomTag.nKv = (ushort)nVal;
                    m_cGenFeedBack.DR_KV = nVal;
                    m_cGlobalData.m_cTaurenComm.SetKvToOTC(nVal);

                    break;
                case KrayGenDll.GEN_MA_MSG:         //普通摄影Ma值
                    m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- DR-MA=" + Convert.ToString(nVal));
                    fMa = Math.Round(nVal / 10.0f, 1);//保留一位小数
                    m_cGlobalData.m_StudyDicomTag.fMa = (float)fMa;
                    m_cGenFeedBack.DR_MA = (float)fMa;
                    m_cGlobalData.m_cTaurenComm.SetMaToOTC((float)fMa);

                    break;
                case KrayGenDll.GEN_MS_MSG:        //普通摄影Ms值
                    m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- DR-MS=" + Convert.ToString(nVal));
                    fMs = Math.Round(nVal / 100.0f, 1);
                    m_cGlobalData.m_StudyDicomTag.nMs = (ushort)fMs;
                    m_cGenFeedBack.DR_MS = (float)fMs;
                    m_cGlobalData.m_cTaurenComm.SetMsToOTC((float)fMs);

                    break;
                case KrayGenDll.GEN_MX_MSG:        //普通摄影Mas值
                    fMas = Math.Round(nVal / 1000.0f, 1);
                    m_cGlobalData.m_StudyDicomTag.fMas = (float)fMas;
                    m_cGenFeedBack.DR_MX = (float)fMas;
                    m_cGlobalData.m_cTaurenComm.SetMasToOTC((float)fMas);

                    break;
                case KrayGenDll.GEN_FO_MSG:        //普通摄影焦点值
                    m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- GenFocus=" + Convert.ToString(nVal));
                    SetGenFocusUI(nVal);
                    break;
                case KrayGenDll.GEN_AECFN_MSG:     //AEC模式密度值
                    break;
                case KrayGenDll.GEN_AECFI_MSG:     //AEC场值
                    m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- AecCFI=" + Convert.ToString(nVal));
                    SetAecFieldStatus(nVal);
                    break;
                case KrayGenDll.GEN_AECFS_MSG:     //AEC屏速值
                    break;
                case KrayGenDll.GEN_AECAT_MSG:     //AEC实际曝光时间值
                    break;
                case KrayGenDll.GEN_TE_MSG:        //摄影技术值(0:MA-MS曝光 1:MAS曝光 2:AEC曝光)
                    SetExpTechModeUI(nVal);
                    m_cStudyEventProc.m_nExpTechMode = nVal;
                    break;
                case KrayGenDll.GEN_ELERROR_MSG:
                    m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- Error:EL" + Convert.ToString(nVal));
                    RayImageErrorCode.AppearErrorInfo(nVal);
                    break;
                case KrayGenDll.GEN_ERERROR_MSG:
                    m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- Error:ER" + Convert.ToString(nVal));
                    RayImageErrorCode.AppearErrorInfo(nVal);
                    break;
                case KrayGenDll.GEN_INIT_MSG:
                    GenGeneralError.AppearErrorInfo(nVal,"");
                    break;
                case KrayGenDll.GEN_CLEARERROR_MSG:
                    RayImageErrorCode.RemoveErrorInfo();
                    break;
                case KrayGenDll.GEN_KEEPLIVE_MSG:  //高压断开通讯
                    GenGeneralError.AppearErrorInfo(5, "");
                     break;
                case KrayGenDll.GEN_LOAD_MSG://高压加载状态消息
                    GenGeneralError.AppearErrorInfo(1, "");
                    break;
                default:
                    break;
            }
        }

       以上几个步骤,我们知道了m_fDRUpdateUIInfo委托最后指向了形参ICallBack委托所执行的函数 UpdateGenDRFunProc(int nCmd, int nVal),也就是说m_fDRUpdateUIInfo会执行函数 UpdateGenDRFunProc(int nCmd, int nVal)。

      这个时候,我们用m_fDRUpdateUIInfo(nCmd,nVal)委托,就能将参数传递给UpdateGenDRFunProc(int nCmd, int nVal)函数,并执行该函数。

     说白了,m_fDRUpdateUIInfo(nCmd,nVal)委托就是指向了UpdateGenDRFunProc(int nCmd, int nVal)函数的地址。

第七部 总结:我们回过头来捋一捋整体的思路。

        委托m_fDRUpdateUIInfo—指向—> 委托形参ICallBack—指向—>SetDRUIUpdate的实参DRGenUpdateUIFun。最后,委托就是指向了实参的地址。

 

你可能感兴趣的:(----------,【C#.基础】)