说说委托是个什么东西,以及委托有什么用
说说委托是个什么东西,以及委托有什么用
定义:委托是一种知道如何调用方法的对象
// 定义一个委托,这个委托定义了通过此委托调用的方法必须是接收一个字符串参数,返回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个参数的方法,但是必须有一个返回值
有没有觉得很神奇,Action
和Func
都是不限制方法类型的,其实,这是因为它们都是泛型委托,委托也可以是泛型的,所以它们可以是接收任意类型的方法
而接收0到16个参数,是因为它们有多个重载版本,Framework都给我们写好了,一般情况下,Action
和Func
就足够我们使用了,几乎遇不上自己声明委托的情况了
委托相等
当比较两个委托是否相等时,并不是比较它的参数和返回类型,而是比较它们注册的方法,如果两个委托实例中注册的方法一模一样,那么这两个委托实例相等,否则不相等