面试被提问,先来浅析C#中的委托

152 阅读4分钟

开篇碎碎念

今天的主角是 C# 中重要概念之一,委托。在汉语解释中,委托也叫代理,就是把事情交给别人去办,比如生活中有委托律师代理打官司。C# 中如果将一个方法委托给一个对象,这个对象就可以代理这个方法的执行。使用委托需要先定义委托,声明委托能代理什么类型的方法,就好比如房产中介能代理抵押贷款业务而不能代理打官司一样。

如何理解委托

委托是一种存储函数引用的类型。这句话中有两个关键点:

  • 通过委托存储函数

    委托可以看作为类似于函数指针的机制,我们知道在 C、C++ 中,函数指针可以存储函数的地址,以便可以通过函数指针调用函数。

    我们先来理解函数指针。

    我们知道函数调用基本方式有直接调用、间接调用。直接调用是通过函数名来调用函数,而间接调用则可以是通过函数指针来调用函数,CPU 通过读取函数指针存储的值来获得函数所在的地址。

    如下为直接调用:

    #include<stdio.h>
    ​
    int Add(int a,int b){
        int result = a + b;
        return result;
    }
    ​
    int main(){
        int x = 10;
        int y = 20;
        int res1 = 0;
    ​
        // 直接调用
        res1 = Add(x,y);
        printf("直接调用函数: %d+%d=%d",x,y,res1);    
    

    如下为使用函数指针来进行间接调用:

    #include<stdio.h>
    ​
    typedef int(*Calc)(int a,int b);
    ​
    int Add(int a,int b){
        int result = a + b;
        return result;
    }
    ​
    int main(){
        int x = 10;
        int y = 20;
        int res1 = 0;
        int res2 = 0;
        
        // 通过函数指针间接调用
        Calc func = &Add;
        res2 = func(x,y);
        printf("间接调用函数: %d+%d=%d",x,y,res2);
    }
    

    2.png

    但与C函数指针不同的是,委托是面向对象的、类型安全和可靠的。

  • 委托是一种类型

    委托是一种类,在定义了委托后,就可以声明该委托类型的变量。委托的声明非常类似于函数,但不带函数体,且需要使用 delegate 关键字。委托的类型由委托的名称确定

委托如何使用

通过上面的介绍,相信大家对委托已经有了个大概的认识。委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用,委托用于将方法作为参数传递给其他方法。

下面从内置的委托类型和自定义委托来阐述。

内置的委托

  • Action :void,且无形参

  • Func :具有返回值

    internal class Program
    {
        static void Main(string[] args)
        {
            Calculation calculation = new Calculation();
    ​
            // 直接调用 Report 方法
            calculation.Report();
    ​
            // 间接调用
            // 声明委托变量并初始化
            Action action = new Action(calculation.Report);
            action.Invoke();
    ​
            // Func 委托类型
            Func<int,int,int> func1 = new Func<int, int, int>(calculation.Add);
            Func<int,int,int> func2 = new Func<int, int, int> (calculation.Sub);
    ​
            int param1 = 10;
            int param2 = 20;
            int res = 0;
            
            res = func1.Invoke(param1, param2);
            Console.WriteLine($"param1 + param2 = {res}");
    ​
            res = func2.Invoke(param1, param2);
            Console.WriteLine($"param1 - param2 = {res}");
            Console.ReadKey();
        }
    }
    ​
    class Calculation
    {
        public void Report()
        {
            Console.WriteLine(" I have 3 methods: ");
        }
    ​
        public int Add(int param1,int param2)
        {
            int result = param1 + param2;
            return result;
        }
    ​
        public int Sub(int param1, int param2)
        {
            int result = param1 - param2;
            return result;
        }
    }
    

3.png

在 C# 中要将一个非静态的方法用于委托,需要先创建一个方法所属类的实例,然后将该实例的方法绑定到委托。

自定义委托

  1. 定义委托

    delegate double Calc(double x,double y);
    
  2. 声明委托类型的变量并初始化

    Calc calc1; 
    // 把委托类型的变量初始化为与委托具有相同返回类型和参数列表的函数引用
    calc1 = new Calc(Add);
    
  3. 调用委托

    // 通过委托间接调用四个方法
    res = calc1.Invoke(a,b);
    

    还是就上面的两数相加,举个栗子:

    class Program
    {
        delegate double Calc(double param1, double param2);
    ​
        static double Add(double param1, double param2) => param1 + param2;
        static void Main(string[] args)
        {
            double param1 = 10;
            double param2 = 20;
            Calc calc1;
            calc1 = new Calc(Add);
            Console.WriteLine($"param1 + param2 = {calc1(param1,param2)}");
        }
    }
        
    

1.png

要把一个函数引用赋给委托变量,需要使用 new 关键字创建一个新委托,指定委托类型,提供一个引用所需函数的参数,即Add,参数是要使用函数名且不带括号。给委托变量赋值也可以这么写:

    calc1 = Add;

最后

委托是C#中的重要概念,在事件的学习中会经常看到此身影,本文只列出部分基础知识点,更多用法可以等待后续更新或直接上官网进行学习。感谢你花了几分钟时间阅读本文,欢迎留言讨论或吐槽!😜