为了账号安全,请及时绑定邮箱和手机立即绑定

委托

标签:
.NET

委托是寻址方法的.NET版本,在C++中,函数指针指向的是一个内存位置,无法判断这个指针指向的实际内容(像参数和返回类型更无从知晓),所以不是类型安全的。在.NET中,委托是类型安全的,它定义了返回类型和参数的类型。委托可以包含对多个方法的引用

从上面这段话中可以看出,委托的实质是一个函数引用,指向的是函数在内存中的地址,且只能指向它定义时声明的具有相同函数签名和返回值的函数。
委托指向的函数与C++中函数指针还存在不同的地方是,函数指针只能指向一个函数地址,而委托可以包含多个方法的引用。函数指针可以作为参数传递给方法,委托也可以作为参数传递给方法。

委托的使用

委托的使用和类的使用差不多,都分为两个阶段:定义和实例化。定义委托就是要告诉编译器这个委托要表示那种类型的方法。语法如下:

delegate void AddInvoker(int x,int y);

delegate 是委托的关键字,AddInvoker是委托的名字,void Xxx(int,int)表示这个委托(AddInvoker)指向的函数,必须满足这样的签名和返回值,即,函数必须有两个int类型作为参数,且无返回值(void)。由上面的定义可以看出,委托的类型安全的(可以与C++函数指针对比),因为在定义委托时,就必须给出它要指向的方法的签名和返回类型等全部的细节。

那么,可以在代码的什么位置定义委托呢?上面说了委托这种类型和class很相似,其定义的地方也和类一样,我们可以在那些地方定义类呢?命名空间内定义一个常规的类,或在类的内部定义一个内部类,委托也是如此,我们可以在类的内部定义,也可在类的外部定义委托。class有访问修饰符:public,private,protected,委托同样可以加上访问修饰符。

实际上,委托就是一个类,他的父类System.MulticastDelegate,继承自System.Delegate类。在编译阶段,编译器会识别Delegate这个类,并使用委托语法的特殊处理。

public class Todo{
    //定义委托
    delegate void PrintDelegate(string msg);    public void start(){        //实例化委托,通过lambda表达式
        var printDelegate = new PrintDelegate((string msg) =>
        {
            Console.WriteLine($"lambda函数打印:{msg}");
        });        //追加方法到委托
        printDelegate += PrintMethod;        //调用委托
        printDelegate("Hello World!");
    }    void PrintMethod(string msg){
        Console.WriteLine($"PrintMethod函数打印:{msg}");
    }    public static void Main(string[] args)
    {
        Todo todo = new Todo();
        todo.start();
        Console.ReadLine();
    }
}

Action<T>和Func<T>委托

因为委托在实际开发中会经常使用,.NET框架为我们预定义了一些常见的委托,Action和Func两种类型的委托,其实可以看做为委托的语法糖。先看Action<T> ,他是代表的是一类无返回值得委托,T表示定义的方法参数类型,最多可以支持8个参数,看看示例:

public void startAction(){    /*
    使用了Action<T>的类型的委托,即action委托定义为代表 void Xxx(string)类型的函数。
    用lambda表达式初始化了action委托对象。
    */
    Action<string> action = msg =>
    {
        Console.WriteLine($"匿名函数打印:{msg}");
    };    //追加方法到委托
    action += PrintMethod;    //调用委托
    action("Hello World!");
}

Func<T>表示具有返回值的委托类型,返回值的类型是最后一个T参数,最多支持16个参数。示例:

/// <summary>/// 定义了一个Add函数,它需要三种类型的参数,T1,T2,T3,返回T3类型的值
/// </summary>/// <returns>返回类型为T3</returns>/// <param name="func">Func委托作为参数,这个委托接受T1和T2作为参数,T3作为委托的回值</param>/// <param name="x">T1类型参数</param>/// <param name="y">T2类型参数</param>/// <typeparam name="T1">T1代表一种类型</typeparam>/// <typeparam name="T2">T2代表一种类型</typeparam>/// <typeparam name="T3">T3代表一种类型</typeparam>public T3 Add<T1,T2,T3>(Func<T1, T2, T3> func, T1 x, T2 y)
{
    return func(x, y);
}

小结

委托是一个特殊类,因为编译器在识别它是委托类后,会按委托的语法处理该类。如果把委托想成一个容器,那它里面装的是多个具有相同签名和返回值的函数的引用,即委托是对一类函数的引用。而这一类函数的特征(返回值和签名)在委托定义时已描述。追加方法的引用到委托可以使用+=操作符。



作者:书上得来终觉浅
链接:https://www.jianshu.com/p/8b47be118f6d


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消