面试官:你了解过委托吗?(上)

215 阅读2分钟

首先我们发出一个问题,什么是委托?

委托是一个对象,它知道如何调用一个方法。

它有两个定义:委托类型和委托实例。

委托类型:委托类型定义了委托实例可以调用的那类方法。

具体来说,委托类型定义了方法的返回类型和参数。可以看个例子:

//delegate定义了一个委托,声明了int类型的返回值
//声明了一个int类型的参数
delegate int Transformer(int x);
    
    //定义了一个方法,具有相同类型的返回类型,
    //和返回参数,此时可以使用委托进行调用.
    static int Square(int x)
    {
        return x*x;
    }
    //lamda表达式的方式,跟上面方法一样.
    public int Square(int x) => x*x;

委托实例:把方法赋值给委托变量的时候就创建了委托实例。相当于实例化使用的过程。例如:

//将一个方法赋值给委托,此时以及实例化
Transformer t = Square;
int result = t(3); //result is 9

完整的使用例子如下:

delegate int Transformer (int x);
        static void Main(string[] args)
        {
            Transformer t = new Transformer(Square);//完整写法
            int result = t.Invoke(3);//完整调用
            Console.Writeline(result);//console result is 9
        }
        static int Square (int x)
        {
            return x*x;
        }

委托的实例其实就是调用者的委托:调用者调用委托,然后委托调用目标方法。

这样有什么好处呢?可以把调用者和目标方法间接的解耦合,同时也可以复用。

我们使用技术时,就需要考虑为什么要这么用,使用委托可以用来做什么?

可以编写插件,因为方法是在运行时才赋值给委托的。

delegate int Transformer (int x);

    public class Util
    {
        //定义一个传递数组和一个委托参数的方法.
        public static void Transform(int[] values,Transformer t)
        {
            for (var i = 0; i < values.Lenght; i++)
            {
                values[i] = t(values[i]);
            }
        }
    }
    class Program
    {
        
        static void Main(string[] args)
        {
            int[] values = {1,2,3};
            //使用的时候传递数组和对应的目标方法
            Util.Transform(values,Square);
            foreach (var item in values)
            {
                Console.Writeline(item);
            }
            
        }

        static int Square (int x)
        {
            return x*x;
        }
    }

多播委托:所有的委托实例都具有多播的能力。一个委托实例可以引用一组目标方法。

就是执行多个委托实例,使用“+”,“+=”操作符可以合并委托实例。

//调用md的时候,同时会调用Delegate1和Delegate2
MultiDelegate md = Delegate1;
//委托的调用顺序与它们定义的顺序一致
md += Delegate2;
//使用 "-"","-="操作符则是把右边的委托从左边的委托移除
md-= Delegate2;

委托的所有类型都是派生于 System.MulticastDelegate,而它又派生于System.Delegate。

C#会把作用于委托的 +,-,+=,-=操作编译成使用system.Delegate的Combine和Remove两个静态方法。