换个角度看委托

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:
毛主席说过长征是宣言书,长征是宣传队,长征是播种机。那么委托是什么呢?
 

阅读目录:

一、 委托是函数模板

二、委托是函数指针

三、委托是函数指针集合

四、委托是事件通知

五、委托是外部帮手

六、.net中定义的丰富多彩的委托

一、 委托是函数模板

和类做对比, 类是对象的模板, 那么委托就是函数的模板.
先看看平常我们如何定义一个class
public class ClassA{
}
如上,我们使用关键字class来定义一个类.
 
对于委托,我们使用delagate来定义:
public delegate void MyDelegate(string a);
我们定义了一个MyDelegate类型, 它定义的函数模板要求: 函数有个sting类型的参数, 没有返回值.
 

二、 委托是函数指针

使用定义好的委托类型,就可以创建这种类型的变量,并且为这种类型的变量赋值.
一个具体的委托变量就是一个函数指针,它指向一个函数的入口,当调用这个委托的时候,就相当于调用这个函数
  • 使用函数赋值
void ShowMessage(string message)
{
    Console.WriteLine(message);
}
那么我们可以这样写
var myDelegate = new MyDelegate(ShowMessage); //创建了一个委托变量,为委托变量赋值
myDelegate("hello"); //直接调用委托, 相当于调用了方法ShowMessage.
 
还可以赋值:
MyDelegate myDelegate = ShowMessage;
 
  • 使用匿名方法赋值
MyDelegate myDelegate = delegate(string message) { Console.WriteLine(message);} //创建了一个委托变量,使用匿名函数赋值
myDelegate("hello"); //直接调用委托, 相当于调用了方法ShowMessage.
 
  • 使用lambda表达式赋值
MyDelegate myDelegate = message => Console.WriteLine(message)//创建了一个委托变量,使用lambda赋值
myDelegate("hello"); //直接调用委托, 相当于调用了方法ShowMessage.
 
 

三. 委托是函数指针集合

复制代码
MyDelegate myDelegate = message => Console.WriteLine(message);//创建了一个委托变量,使用lambda赋值
myDelegate += ShowMessage;//对委托变量,增加一个函数
myDelegate("hello");
 
public static void ShowMessage(string message)
{
    Console.WriteLine(message + "1");
}
复制代码
输出结果是
 
可以看到, 我们在调用myDelegate的时候, 输出了2个message(hello和hello1), 一个是lambda表达式定义的函数,一个是ShowMessage函数
这里委托就像是一个函数指针的集合类,包含了对2个方法的引用,当调用该委托的时候,就调用了这2个方法。
 

四. 委托是事件通知

假设当前你要设计一个仓库类,每个仓库都有一定的大小,当超过了仓库大小的时候, 你要把这个事件报告出来. 其它类可以容易的获取到这个事件和处理这个事件。
复制代码
class Program
{
    static void Main(string[] args)
    {
        var warehouses = new Warehouses(100);//定义了一个大小是100的仓库
        warehouses.WarehousesOverFlowEvent += WhenWarehousesOverFlow;//对仓库进行监控
        warehouses.Add(120);
        Console.ReadLine();
    }
    static void WhenWarehousesOverFlow(Warehouses warehouses, int changeNumber)//这个是对于仓库溢出的处理函数
    {
         Console.WriteLine("The current warehouse is overflow, we need do something.");
    }
}
 
public delegate void WarehousesOverFlow(Warehouses warehouses, int changeNumber);//定义委托类型,从名字很容易明白这个委托是用来通知仓库溢出的事件的.
public class Warehouses
{
    private readonly int _storesSize;
    private int _currentSize = 0;
    public WarehousesOverFlow WarehousesOverFlowEvent { set; get; }//定义了一个public的委托, 任何外界对象对于该仓库的溢出感兴趣的对象,都可以为WarehousesOverFlowEvent指定一个具体的响应函数
    public Warehouses(int storesSize)
    {
        _storesSize = storesSize;//在构造函数中,指定了仓库的size
    }
    public bool Add(int number)
    {
        if(_currentSize + number > _storesSize)//如果添加的货物数量大于了size, 就通过委托通知外界
        {
             if (WarehousesOverFlowEvent != null) WarehousesOverFlowEvent(this, number);
             return false;
        }
        _currentSize += number;
        return true;
     }
}
复制代码

 

运行之后的结果会看到:
 
我们熟悉的asp.net和winform中的事件event也是委托. 上面的例子中, 对于面向对象的"开放封闭"原则, 通过委托就非常优雅的实现了。它封闭了仓库自己的功能, 同时又开放了外界获取信息的渠道。
 

五. 委托是外部帮手

下面的例子中, 实现了一个Log类, 用来记录日志,但是log类真实的记录动作不是有它自己完成的,而是通过委托完成的. 这里的委托就充当了一个外部帮手中介的角色.
当我们为它的委托指定为ConsoleWriter的时候, 就把日志输出到控制台
当为它指定为FileWriter的时候,就把日志输出到文件
当指定为DbWriter的时候,它又把日志输出到数据库了。
 
复制代码
class Program
{
    static void Main(string[] args)
    {
        var log = new Log();
        log.WriteMessage += ConsoleWriter; //为委托指定为控制台输出
        Console.ReadLine();
    }
    //输出日志到控制台
    static void ConsoleWriter(string message)
    {
        Console.WriteLine(message);
    }
    static void FileWriter(string message)
    {
        ........
    }
    static void DbWriter(string message)
    {
        ........
    }
}
public delegate void WriteMessage(string message);
public class Log
{
    public WriteMessage WriteMessage { get; set; }
    public void Debug(string message)
    {
        if (WriteMessage != null) WriteMessage(message);
    }
    public void Info(string message)
    {
        if (WriteMessage != null) WriteMessage(message);
    }
}
复制代码
 

六. .net中定义的丰富多彩的委托

  • EventHandler
其定义public delegate void EventHandler(object sender, System.EventArgs e)
  • Func
其定义之一:public delegate TResult Func<in T1,in T2,out TResult>(T1 arg1, T2 arg2)
  • Action
其定义之一:public delegate void Action<in T>(T obj)
  • Predicate
其定义:public delegate bool Predicate<in T>(T obj)
有了.net中已经为我们定义好了的委托类型,能够满足我们的大部分需求了,所以在使用委托的时候,尽量避免定义过多的委托类型.


本文转自JustRun博客园博客,原文链接:http://www.cnblogs.com/JustRun1983/archive/2013/04/21/What_is_Delegate.html,如需转载请自行联系原作者

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1月前
|
Java 编译器 程序员
Java多态背后的秘密:动态绑定如何工作?
本文介绍了Java中多态的实现原理,通过动态绑定和虚拟方法表,使得父类引用可以调用子类的方法,增强了代码的灵活性和可维护性。文中通过具体示例详细解析了多态的工作机制。
44 4
|
3月前
|
设计模式
学会了这个设计模式,再也不是只会写if/else了
本文详细介绍了责任链设计模式(Chain of Responsibility Pattern),这是一种行为型设计模式,用于创建一个接收者对象的链,通过解耦请求的发送者和接收者,允许沿着链传递请求,直到某个接收者能够处理它。
学会了这个设计模式,再也不是只会写if/else了
|
设计模式 人工智能 前端开发
彻底说透简单工厂那些你没有关注过的细节
接下来看代码,还是以创建一门网络课程为例。假设有Java架构、大数据、人工智能等课程,已经形成了一个生态。我们可以定义一个课程标准ICourse接口。
69 0
|
小程序 编译器 C语言
c++重中之重:“换个龟壳继续套娃“:运算符重载等的学习
c++重中之重:“换个龟壳继续套娃“:运算符重载等的学习
126 0
|
存储 编译器 C++
C++继承和多态核心重点知识刨析,一文必拿下
C++继承和多态核心重点知识刨析,一文必拿下
C++继承和多态核心重点知识刨析,一文必拿下
|
设计模式 安全 Java
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(2)
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(2)
142 0
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(2)
|
设计模式
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(1)
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(1)
153 0
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(1)
|
编译器 C# C++
我竟然用它搞懂了王者荣耀的技能释放机制!【C#委托】
我竟然用它搞懂了王者荣耀的技能释放机制!【C#委托】
264 0
|
Java
你以为工厂模式很简单,可能是因为你懂的只是冰山的一角
工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
19125 0
|
Web App开发 Android开发 存储
换个角度看问题
换个角度看问题,可以节省你大量时间,提高你的效率。 背景 公司开发的一个 app,有用户反馈在打开网页点击上传图片按钮时,点击拍照不能唤起系统相机。
1162 0