• 什么是委托,非自定义委托与自定义委托


    C语言中的函数指针:


    一切皆地址:
    程序的本质是变量+算法
    变量是以变量名对应内存地址为起点的一段内存,其所存储的数据就是变量里的数据,这段内存的大小由变量的数据类型决定->变量是地址。
    函数是以函数名对应的内存地址为起点的一段内存,这段内存存储的不是某个值,而是一组机器语言的指令,CPU按照这组指令一条条执行,完成我们函数中所包含的算法->函数是地址。

    直接调用与间接调用的本质:
    直接调用:
    CPU通过函数名找到这段地址,然后执行指令,执行完最后一条,CPU返回到调用者那里去。
    间接调用:
    CPU通过某个指向某函数的函数指针来间接调用函数,函数指针是一个变量,它存储函数名所对应的那个地址,找到地址后,后面是一样的。

    C#通过委托来保留C语言中的间接调用功能,Java则完全舍弃了这部分功能,禁止直接访问内存。

    委托就是函数指针的升级。

    C语言中需要先声明函数指针类型,才能使用这个类型。
    而C#类库中已经为我们准备好了很多可以直接使用的委托类型。
    常用的有Action(无返回值的方法专用),Function等
    举个例子,我们建一个计算器类:

        class Calculator
        {
            public void Report()
            {
                Console.WriteLine("I have 3 methods.");
            }
            public int Add(int a, int b)
            {
                int result = a + b;
                return result;
            }
    
            public int Sub(int a, int b)
            {
                int result = a - b;
                return result;
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Calculator calculator = new Calculator();
                Action action = new Action(calculator.Report);
                calculator.Report();//直接调用
                action.Invoke();//间接调用(使用action委托)
                action(); //间接调用的简洁版
            }
        }
    

    代码分析,Calculator是计算器类,我们建立它的实例calculator然后,
    建立Action实例action,它的构造函数要求我们输入一个:
    参数列表为空,无返回值(返回值为void)的方法。

    Report方法满足这个条件。
    所以:
    Action委托是专门应对——无返回值(返回值为void)的方法的。

    对于有返回类型和有参数的方法,我们使用Func委托:


    Func<>委托有若干的重载,前面的是参数类型,最后一项是返回值类型。

    在这里我们用第二种。

    要求我们在Func的构造函数里填写匹配的方法,我们写入Add和Sub方法。

        class Program
        {
            static void Main(string[] args)
            {
                Calculator calculator = new Calculator();
                Func<int, int, int> func1 = new Func<int, int, int>(calculator.Add);
                Func<int, int, int> func2 = new Func<int, int, int>(calculator.Sub);
                int z = 0;
                z = func1.Invoke(100, 200);//间接调用(使用Func委托),还可以简写为z = func1(200,100);
                Console.WriteLine(z);
                z = func2.Invoke(100, 200);//间接调用(使用Func委托)
                Console.WriteLine(z);
            }
        }
    

    委托是个类,我们来验证一下

    using System;
    using System.Collections.Generic;
    
    namespace CustomizeDelegate
    
    {
    
      class Program
      {
        static void Main(string[] args)  
        {
          Type t = typeof(Action);
          Console.WriteLine(t.IsClass);//返回true,说明Action委托是类
    
        }
    
      }
    
    }
    

    程序结果:
    true
    所以证明委托是个类。

    自定义一个委托:

    参数类型,返回类型必须一一对应(名称可以不同)

    委托类,因为是类,与其他类平级,所以声明在命名空间里,他的声明格式是仿照函数指针。

        public delegate double Calc{double x, double y};
    

    定义一个计算机类Calculator

        class Calculator
        {
            public double Add(double x, double y)
            {
                return x + y;
            }
            public double Sub(double x, double y)
            {
                return x - y;
            }
            public double Mul(double x, double y)
            {
                return x * y;
            }
            public double Div(double x, double y)
            {
                return x / y;
            }
        }
    

    创建Calculator类实例calculator ,然后创建Calc委托的实例calcAdd等等。

        class Program
        {
            static void Main(string[] args)
            {
                Calculator calculator = new Calculator();
    
                Calc calcAdd = new Calc(calculator .Add);
                Calc calcSub = new Calc(calculator .Sub);
                Calc calcMul = new Calc(calculator .Mul);
                Calc calcDiv = new Calc(calculator .Div);
    
                double result = 0;
    
                result  = calcAdd.Invoke(100, 200);//间接调用(使用Calc委托)
                Console.WriteLine(result);
                result  = calcSub(100, 200);//间接调用(使用Calc委托)
                Console.WriteLine(result);
                result  = calcMul(100, 200);//间接调用(使用Calc委托)
                Console.WriteLine(result);
                result  = calcDiv(100, 200);//间接调用(使用Calc委托)
                Console.WriteLine(result);
            }
        }
    

    结果是:

  • 相关阅读:
    OC-内存管理-基本原理与引用计数器
    OC-改错题
    OC-Q&A
    OC-SEL
    CO-类的本质、description方法
    Tomcat 下 mysql的连接池配置和使用
    转:JAVA.NET.SOCKETEXCEPTION: TOO MANY OPEN FILES解决方法
    使应用程序常驻内存,不能被任务管理器关闭之配置文件设置
    解决Tomcat catalina.out 不断成长导致档案过大的问题
    >/dev/null 2>&1的含义
  • 原文地址:https://www.cnblogs.com/maomaodesu/p/11393254.html
Copyright © 2020-2023  润新知