说说委托是个什么东西,以及委托有什么用

说说委托是个什么东西,以及委托有什么用

定义:委托是一种知道如何调用方法的对象

// 定义一个委托,这个委托定义了通过此委托调用的方法必须是接收一个字符串参数,返回int类型
delegate int OneDelegate(string s);

// 委托是一个对象,所以在使用委托时也需要创建实例
OneDelegate one = null;

委托是一个帮手,是一个集合

先说委托是什么东西,委托是一个帮手,是一个集合,为什么这么说呢,因为它就是这么用的

结合实际例子来说

// 这是一个简单的例子,我们从请假的角度来说委托
using System;

//定义一个委托对象,这个委托定义了通过此委托调用的方法必须是接收一个字符串参数,没有返回值(返回类型为void)
delegate void LeaveDelegate(string s);

class Program
{
    static void Main(string[] args)
    {
        Student b = new Student("蓝精灵"); // 创建学生实例蓝精灵
        // b调用请假方法,传递一个委托
        b.Leave(Teachers.OneStudentLeave); // 直接传递一个满足委托要求的方法,相当于实例化一个委托变量并将方法注册到这个委托变量再传递给Leave方法
    }
}

class Student
{
    private readonly string _name;

    public Student(string name)
    {
        _name = name;
    }
    // 请假,需要一个委托形参
    public void Leave(LeaveDelegate e)
    {
        e(_name);
    }
}
// 老师类
class Teachers
{
    // 登记请假
    public static void OneStudentLeave(string name)
    {
        // 学生请假
        Console.WriteLine(name +"我已收到你的请假申请");

        // 一个简单例子,忽略数据库操作
    }
}

为什么用委托

在这个例子中,Leave方法调用委托,委托调用OneStudentLeave方法,这种间接调用的方式将调用者和目标方法解耦,解耦之后更有利于单元测试,不用一定等到老师的请假方法写好了才能测试学生的Leave的方法是否正确;在需求改动的时候,也无需再对Leave方法进行修改

能用委托的也可以用接口,但以下情况建议使用委托

  • 接口内仅定义了一个方法
  • 需要多播能力
  • 订阅者需要多次实现接口

满足以上条件一个或多个时建议使用委托,因为在以上任意一种情况下,使用接口的代码量会远远超过使用委托,并且可维护性也不如使用委托,如果有疑问可以把本文中的例子用接口实现一遍,便能够明白

多播委托更强大

所有的委托实例都拥有多播能力。这意味着一个委托可以引用任意个方法,在之前的例子中,委托只引用了一个方法,假设现在请假除了要告知老师,还要告知校长,那么我们的代码会有多少变化?

using System;

//定义一个委托对象,这个委托定义了通过此委托调用的方法必须是接收一个字符串参数,没有返回值(返回类型为void)
delegate void LeaveDelegate(string s);

class Program
{
    static void Main(string[] args)
    {
        Student b = new Student("蓝精灵"); // 创建学生实例蓝精灵

        // 声明一个委托变量e,将Teachers.OneStudentLeave方法添加到引用
        LeaveDelegate e = Teachers.OneStudentLeave;
        // President.OneStudentLeave方法添加到引用e
        // 此时e保存了两个方法的引用
        e += President.OneStudentLeave;
        
        // b调用请假方法,传递一个委托
        b.Leave(e); 
    }
}

class Student
{
    private readonly string _name;

    public Student(string name)
    {
        _name = name;
    }
    // 请假,需要一个委托形参
    public void Leave(LeaveDelegate e)
    {
        e(_name);
    }
}
// 老师类
class Teachers
{
    // 登记请假
    public static void OneStudentLeave(string name)
    {
        // 学生请假
        Console.WriteLine(name +"我已收到你的请假申请");

        // 一个简单例子,忽略数据库操作
    }
}

class President
{
    public static void OneStudentLeave(string name)
    {
        Console.WriteLine(name + "我同意了你的请假");
    }
}

这是使用了多播委托的情况,面对增加向校长请假的需求变更,新增了校长类,然后将校长的OneStudentLeave方法注册到委托中,没有修改老师类,也没有修改学生类,也没有因为需要向多个人申请而添加新的方法

何必自己定义委托

自从C# 2.0之后,C#有了Func委托和Action委托

这两个委托是Framework提前定义好的,我们可以直接拿来用

Action委托可以接收0到16个参数的方法

Func委托也可以接收0到16个参数的方法,但是必须有一个返回值

有没有觉得很神奇,ActionFunc都是不限制方法类型的,其实,这是因为它们都是泛型委托,委托也可以是泛型的,所以它们可以是接收任意类型的方法

而接收0到16个参数,是因为它们有多个重载版本,Framework都给我们写好了,一般情况下,ActionFunc就足够我们使用了,几乎遇不上自己声明委托的情况了

委托相等

当比较两个委托是否相等时,并不是比较它的参数和返回类型,而是比较它们注册的方法,如果两个委托实例中注册的方法一模一样,那么这两个委托实例相等,否则不相等

posted @ 2020-07-28 16:49  吴俊城  阅读(824)  评论(0编辑  收藏  举报