• C#入门详解(10)


    什么是委托

    委托是函数指针的升级版

    实例:C/C++中的函数指针

    一切皆地址

    变量(数据)是以莫个地址为起点的一段内存中所存储的值

    函数(算法)是以莫个地址为七点的一段内存中所存储的一组机器语言指令

    直接调用与间接调用

    直接调用:通过函数名来调用函数,CPU是通过函数名来直接获取函数所在的地址并开始执行-》返回

    间接调用:通过函数指针来调用函数,CPU通过读取函数指针存储的值来获得函数所在地址并开始执行-》返回

    委托的简单使用

    Action委托

    Func委托

    委托的声明

    委托是一种类,类是数据类型,所以委托也是一种数据类型

    它的声明方式与一般类不同,主要是为了照顾可读性

    注意声明委托的位置

    避免写错地方结果声明成嵌套类型

    委托与所封装的方法必须类型兼容

    返回值的数据类型一致

    参数列表在个数和数据类型上一致(参数名不需要一样)

    委托的使用

    实例:把方法当作参数传给另一个方法

    正确使用1:模板方法:借用指定的外部方法来产生结果

    相当于填空题

    常位于代码中部

    委托有返回值

    正确使用2:回调方法:调用制定的外部方法

    相当于流水线

    常位于代码尾部

    委托无返回值

    注意:难精通+易使用+功能强大的东西,一旦被滥用则后果非常严重

    缺点1:这是一种方法级别的紧耦合,现实工作中要慎之又慎

    缺点2:使可读性下降,debug的难度增加

    缺点3:把委托回调,异步调用和多线程纠缠在一起,会让代码变得难以阅读和维护

    缺点4:委托使用不当有可能造成内存泄漏和程序性能下降

    实例代码

    模板方法:

    声明三个类,分别是产品类,盒子类,包装类

     class Product
        {
            public string Name { get; set; }
        }
    
        class Box
        {
            public Product Product { get; set; }
        }
    
        class WarpBox
        {
            public Box GetProduct(Func<Product> func)
            {
                Box box = new Box();
                box.Product = func.Invoke();
                return box;
            }
        }

    声明产品工厂类并实现包装盒子类中得Func类型委托

     class ProductFactory
        {
            public Product MakePizaa()
            {
                Product product = new Product();
                product.Name = "Pizaa";
                return product;
            }
            public Product MakeToyCar()
            {
                Product product = new Product();
                product.Name = "ToyCar";
                return product;
            }
        }

    直接调用产品工厂类中的方法

     static void Main(string[] args)
            {
                ProductFactory factory = new ProductFactory();
                WarpBox warpbox = new WarpBox();
                Box box1 = warpbox.GetProduct(factory.MakePizaa);
                Box box2 = warpbox.GetProduct(factory.MakeToyCar);
                Product product1 = box1.Product;
                Product product2 = box2.Product;
                Console.WriteLine(product1.Name);
                Console.WriteLine(product2.Name);
                Console.ReadLine();
            }   

    回调方法:

    增加日志类

        class Logger
        {
            public void MakeLog(Product product)
            {
                    Console.WriteLine(string.Format("产品名{0},它的价格为{1},生产时间为{2}", product.Name, product.Price,DateTime.UtcNow));
            }
        }

    在产品工厂里添加action委托类型参数

     class WarpBox
        {
            public Box GetProduct(Func<Product> func,Action<Product> action)
            {
                Box box = new Box();
                box.Product = func.Invoke();
                if (box.Product.Price>=50)
                {
                    action.Invoke(box.Product);
                }
                
                return box;
            }
        }

    调用

     static void Main(string[] args)
            {
                ProductFactory factory = new ProductFactory();
                WarpBox warpbox = new WarpBox();
                Logger logger = new Logger();
                Box box1 = warpbox.GetProduct(factory.MakePizaa,logger.MakeLog);
                Box box2 = warpbox.GetProduct(factory.MakeToyCar,logger.MakeLog);
                Product product1 = box1.Product;
                Product product2 = box2.Product;
                Console.WriteLine(product1.Name);
                Console.WriteLine(product2.Name);
                Console.ReadLine();
            }   

    委托的高级使用

    多播委托

        class Program
        {
            static void Main(string[] args)
            {
                Student stu1 = new Student { Id = 1, PenColor = ConsoleColor.Cyan };
                Student stu2 = new Student { Id = 2, PenColor = ConsoleColor.Red };
                Student stu3 = new Student { Id = 3, PenColor = ConsoleColor.Yellow };
                Action action1 = new Action(stu1.DoHomeWork);
                Action action2 = new Action(stu2.DoHomeWork);
                Action action3 = new Action(stu3.DoHomeWork);
                action1 += action2;
                action1 += action3;
                action1.Invoke();
            }   
        }
    
        class Student
        {
            public int Id { get; set; }
            public ConsoleColor PenColor { get; set; }
            public void DoHomeWork()
            {
                for (int i = 0; i < 4; i++)
                {
                    Console.ForegroundColor = this.PenColor;
                    Console.WriteLine(string.Format("{0} do homework", this.Id));
                    Thread.Sleep(1000);
                }
            }
        }

     按照封装方法的先后顺序

    隐式异步调用

    基础概念:

    同步:你昨完了我接着做

    异步:我们同时做

    每个运行的程序是一个进程

    每个进程可以拥有多个线程

    差异:

    同步调用是在一个线程下

    异步调用的机理是在多个线程下

    串行-同步-单线程      并行-异步-多线程

    隐式多线程/显示多线程

    直接同步调用:使用方法名

    间接同步调用:使用单播/多播委托invoke方法

    隐式异步调用:使用BeginInvoke方法

    显示异步调用:使用Thread或Task

    直接同步调用代码:

     class Program
        {
            static void Main(string[] args)
            {
                Student stu1 = new Student { Id = 1, PenColor = ConsoleColor.Cyan };
                Student stu2 = new Student { Id = 2, PenColor = ConsoleColor.Red };
                Student stu3 = new Student { Id = 3, PenColor = ConsoleColor.Yellow };
                stu1.DoHomeWork();
                stu2.DoHomeWork();
                stu3.DoHomeWork();
                for (int i = 0; i < 5; i++)
                {
                    Console.ForegroundColor = ConsoleColor.Blue;
                    Console.WriteLine("Main thread is working");
                }
            }   
        }
    
        class Student
        {
            public int Id { get; set; }
            public ConsoleColor PenColor { get; set; }
            public void DoHomeWork()
            {
                for (int i = 0; i < 4; i++)
                {
                    Console.ForegroundColor = this.PenColor;
                    Console.WriteLine(string.Format("{0} do homework", this.Id));
                    Thread.Sleep(1000);
                }
            }
        }

    间接同步调用代码:

     class Program
        {
            static void Main(string[] args)
            {
                Student stu1 = new Student { Id = 1, PenColor = ConsoleColor.Cyan };
                Student stu2 = new Student { Id = 2, PenColor = ConsoleColor.Red };
                Student stu3 = new Student { Id = 3, PenColor = ConsoleColor.Yellow };
                Action action1 = new Action(stu1.DoHomeWork);
                Action action2 = new Action(stu2.DoHomeWork);
                Action action3 = new Action(stu3.DoHomeWork);
                action1.Invoke();
                action2.Invoke();
                action3.Invoke();
                for (int i = 0; i < 5; i++)
                {
                    Console.ForegroundColor = ConsoleColor.Blue;
                    Console.WriteLine("Main thread is working");
                }
            }   
        }
    
        class Student
        {
            public int Id { get; set; }
            public ConsoleColor PenColor { get; set; }
            public void DoHomeWork()
            {
                for (int i = 0; i < 4; i++)
                {
                    Console.ForegroundColor = this.PenColor;
                    Console.WriteLine(string.Format("{0} do homework", this.Id));
                    Thread.Sleep(1000);
                }
            }
        }

    直接同步调用和间接同步调用效果一样。

    隐式的异步调用使用BeginInvoke()方法

    显示的异步调用使用Thread对象或者Task对象

    应该适时地使用接口取代一些对委托的使用

     

     

  • 相关阅读:
    html04
    html03
    html02
    html01
    通过脚本获取form表单的数值而不是submit
    myeclipse自带的数据库查看文件
    如何实现数组和List之间的转换?
    Array和ArrayList有何区别?
    ArrayList和LinkedList的区别是什么?
    如何决定使用HashMap还是TreeMap?
  • 原文地址:https://www.cnblogs.com/jingjingweixiao/p/11001146.html
Copyright © 2020-2023  润新知