什么是委托
委托是函数指针的升级版
实例: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