• C#委托


    C#委托

    23考完复变打算更博的,但是那天顶着38.5°C考完复变之后实在顶不住了,歇了几天

    委托

    委托(delegate)是C/C++里面函数指针的升级版,如果你有一定的C基础,那就知道委托的作用了。在计算机里面一切皆为地址,变量(数据)是以某个地址为起点的一段内存中所存储的值,函数(算法)是以某个地址为起点的一段内存中所存储的一组机器语言指令。函数的调用有两种方法:直接调用和间接调用,直接调用就是直接通过函数的名字来调用,CPU通过函数的名字找到函数存储的位置进而执行;间接调用是用函数指针来调用,CPU通过函数指针存储的地址找到函数所在的地方进而执行。
    C#中的委托是经过包装的函数指针,让你感受不到它是一个指针。但是实际用起来,就是函数指针的用法。C#中的委托可以自己写一个,或者使用C#为你准备好的一些委托,比如Action(无返回值的函数)、Func(有返回值的函数)。
    说了这么多,委托有什么用呢?拿两个经典例子来说:模板方法(template method)和回调方法(callback)。
    多说无益,看例子:

    模板方法

    using System;
    
    namespace SomeNote
    {
        class Program
        {
            static void Main(string[] args)
            {
                ProductFactory productFactory = new ProductFactory();
                WrapFactory wrapFactory = new WrapFactory();
                Box box1 = new Box();
                Box box2 = new Box();
    
                Func<Product> fun1 = productFactory.MakePizza;             //Func这个委托是C#准备好的,它接受一个带返回值,但是没有参数的函数
                Func<Product> fun2 = productFactory.MakeToyCar;            //Func是一个泛型委托,尖括号里面是它的返回值类型
    
                box1 = wrapFactory.WrapProduct(fun1);
                box2 = wrapFactory.WrapProduct(fun2);
    
                Console.WriteLine(box1.Product.Name);
                Console.WriteLine(box2.Product.Name);
            }
        }
    
        class Product
        {
            public string Name { get; set; }
        }
    
        class Box
        {
            public Product Product { get; set; }
        }
    
        class WrapFactory
        {
            public Box WrapProduct(Func<Product> getProduct)             //一个模板方法,接收一个委托,这个委托在方法体里面产生某个结果
            {                                                            //模板方法相当于填空题,你需要什么就放什么进参数表
                Box box = new Box();
                Product product = getProduct.Invoke();
                box.Product = product;
                return box;
            }
        }
    
        class ProductFactory
        {
            public Product MakePizza()
            {
                Product product = new Product();
                product.Name = "Pizza";
                return product;
            }
    
            public Product MakeToyCar()
            {
                Product product = new Product();
                product.Name = "Toy Car";
                return product;
            }
        }
    }
    

    这就是模板方法,借用指定的外部方法来产生结果。WrapProduct这个方法是非常好的一个处理方式,你需要什么就给它什么,模板方法一般出现在代码中间。模板方法的委托一般有返回值,放到方法体里面做各种处理。
    程序的执行结果如下:
    模板方法

    回调方法

    using System;
    
    namespace SomeNote
    {
        class Program
        {
            static void Main(string[] args)
            {
                WrapFactory wrapFactory = new WrapFactory();
                ProductFactory productFactory = new ProductFactory();
                Box box1 = new Box();
                Box box2 = new Box();
                Logger logger = new Logger();
    
                Action<Product> action = new Action<Product>(logger.Log);                 //Action也是C#为我们准备好的一个泛型委托
                Func<Product> func1 = new Func<Product>(productFactory.MakePizza);        //它接收一个没有返回值,参数只有一个的函数,尖括号里面是函数的参数类型
                Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);       //不知道你有没有发现这里声明委托和上面的例子不一样
    
                box1 = wrapFactory.WrapProduct(func1, action);
                box2 = wrapFactory.WrapProduct(func2, action);
    
                Console.WriteLine(box1.Product.Name);
                Console.WriteLine(box2.Product.Name);
            }
        }
    
        class Product
        {
            public string Name { get; set; }
            public double Price { get; set; }
        }
    
        class Box
        {
            public Product Product { get; set; }
        }
    
        class WrapFactory
        {
            public Box WrapProduct(Func<Product> getProduct, Action<Product> logCallback)    //多了一个参数
            {
                Box box = new Box();
                Product product = getProduct.Invoke();
    
                if (product.Price >= 50)                                                     //价格大于50就输出它的价格
                {
                    logCallback(product);
                }
    
                box.Product = product;
                return box;
            }
        }
    
        class ProductFactory
        {
            public Product MakePizza()
            {
                Product product = new Product();
                product.Name = "Pizza";
                product.Price = 60;
                return product;
            }
    
            public Product MakeToyCar()
            {
                Product product = new Product();
                product.Name = "Toy Car";
                product.Price = 30;
                return product;
            }
        }
    
        class Logger                                                                     //这个类只有一个方法,用来实现回调
        {
            public void Log(Product product)
            {
                Console.WriteLine(product.Price);
            }
        }
    }
    

    回调方法的例子我只是在模板方法的基础上稍作修改。注意到WrapProduct这个方法多了一个参数,多接收了一个委托。在方法体里面,多了一个判断价钱是否大于50,这里的ActionLog,输出Product的价格。回调方法相当于一条流水线,你符合就调用,不符合就不调用,它常常位于代码末,它使用的委托没有返回值。
    最后关注一下15、16、17行的代码,与模板方法的例子不一样,这里委托的声明一大串,很复杂。这是什么意思呢?在上一个例子,我们没有说明Func绑定的函数是什么类型的,这是因为编译器会帮我们做推断。而这个例子我们把它说清楚了,它就是一个Func<Product>型的委托,绑定的函数是MakePizza。其实编译器很聪明的,一般我们不用完整说出来它的类型,编译器会帮我们推断。
    最终,程序的运行结果:
    回调方法

    Caution!

    委托有一个很突出的特点:难精通、易使用、功能强大。委托滥用会产生很多不好的后果:

    • 这是一种方法级别的紧耦合,现实工作中要谨慎使用
    • 使可读性下降,debug难度大大增加
    • 把委托回调、异步调用和多线程纠缠在一起,会让代码难以阅读和维护
    • 委托使用不当可能造成内存泄露和程序性能下降

    In a word,委托是好东西,但是用之前要三思。

    碎碎念

    因为复习复变,一个星期没写码了。昨天顶着38度做了博客园客制化,侯捷的课还剩下3节。我觉得我挺拼的,但是好像没什么结果。下周工作室申请那边要答辩了,希望一切顺顺利利吧,为了R社,也为了自己。(其实今天这篇博客也是受狒狒启发才写的)

  • 相关阅读:
    ARM Security Technology
    《Linux/UNIX系统编程手册》第6章 进程
    Go 数组合并去重和排序
    Elasticsearch 删除数据
    Go常用排序算法
    Exception in window.onload: An error has occuredJSPlugin.3005
    基于Flask的 api(四)
    基于Flask的 api(三)
    判断json对象时JSONArray还是JSONObject
    基于Flask的 api(二)
  • 原文地址:https://www.cnblogs.com/Jay-Auditore/p/14033756.html
Copyright © 2020-2023  润新知