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对象

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

 

 

posted @ 2019-06-10 23:34  静静微笑  阅读(546)  评论(0编辑  收藏  举报