019 委托
实例:C/C++中的函数指针
#include <stdio.h> #include <stdlib.h> typedef int(*Calc)(int a, int b); int Add(int a, int b) { return a+b; } int Sub(int a, int b) { return a-b; } int main() { int x = 100; int y = 200; int z; Calc funPiont1 = &Add; Calc funPoint2 = ⋐ z = funPiont1(x,y); printf("%d+%d=%d\n",x,y,z); z=funPoint2(x,y); printf("%d-%d=%d\n",x,y,z); system("pause"); return 0; }
C#中的委托:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo2 { class Program { static void Main(string[] args) { Calcculator calculator = new Calcculator(); Action action = new Action(calculator.Report); calculator.Report(); action.Invoke(); action(); Func<int, int, int> func1 = new Func<int, int, int>(calculator.Add); Func<int, int, int> func2 = new Func<int, int, int>(calculator.Sub); int x = 20; int y = 12; int z = func1(x, y); Console.WriteLine(z); z = func2(x, y); Console.WriteLine(z); } } class Calcculator { public void Report()//报告 { Console.WriteLine("I have 3 methods.");//我有三种方法 } public int Add(int a,int b) { int result = a + b; return result; } public int Sub(int a,int b) { int result = a - b; return result; } } }
C#委托声明(自定义委托)
检测委托是否是一个类(返回结果表示 委托是一个类):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo2 { class Program { static void Main(string[] args) { Type t = typeof(Action); Console.WriteLine(t.IsClass); } } }
自己声明一个委托:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Calculator calculator = new Calculator(); Calc calc1 = new Calc(calculator.Add); Calc calc2 = new Calc(calculator.Sub); Calc calc3 = new Calc(calculator.Mul); Calc calc4 = new Calc(calculator.Div); double a = 100; double b = 200; double c = 0; Console.WriteLine(calc1.Invoke(a,b)); Console.WriteLine(calc2.Invoke(a,b)); Console.WriteLine(calc3(a,b)); Console.WriteLine(calc4(a,b)); } } class Calculator { public double Add(double x, double y) { return x + y; } public double Sub(double x, double y) { return x - y; } public double Mul(double x, double y) { return x * y; } public double Div(double x, double y) { return x / y; } } }
委托的一般使用
实例:把方法当做参数传给另一个方法
正确使用1:模板方法
- 相当于填空题
- 常常位于代码中部
- 委托有返回值
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { ProductFactory productFactory = new ProductFactory(); WrapFactory wrapFactory = new WrapFactory(); Func<Product> func1 = new Func<Product>(productFactory.MakePizza); Func<Product> func2 = new Func<Product>(productFactory.MakeToCar); Box box1 = wrapFactory.WraProduct(func1); Box box2 = wrapFactory.WraProduct(func2); 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 WraProduct(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 MakeToCar() { Product product = new Product(); product.Name = "Toy Car"; return product; } } }
正确使用2:回调(callback)
- 相当于流水线
- 常常位于代码末尾
- 委托无返回值
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { ProductFactory productFactory = new ProductFactory(); WrapFactory wrapFactory = new WrapFactory(); Func<Product> func1 = new Func<Product>(productFactory.MakePizza); Func<Product> func2 = new Func<Product>(productFactory.MakeToCar); Logger logger = new Logger(); Action<Product> log = new Action<Product>(logger.Log); Box box1 = wrapFactory.WraProduct(func1,log); Box box2 = wrapFactory.WraProduct(func2,log); Console.WriteLine(box1.product.Name); Console.WriteLine(box2.product.Name); } } class Logger { public void Log(Product product) { Console.WriteLine("Product'{0}' Create at'{1}'.Price is '{2}'.",product.Name,DateTime.UtcNow,product.Price); } } class Product//产品 { public string Name { get; set; } public double Price { get; set; } } class Box//包装 { public Product product { get; set; } } class WrapFactory//包装工厂 { public Box WraProduct(Func<Product>getProduct,Action<Product>logCallback) { Box box = new Box(); Product product = getProduct.Invoke(); if (product.Price >= 50) { logCallback(product); } box.product = product; return box; } } class ProductFactory//产品工厂 { public Product MakePizza() { Product product = new Product(); product.Name = "Pizza"; product.Price = 12; return product; } public Product MakeToCar() { Product product = new Product(); product.Name = "Toy Car"; product.Price = 100; return product; } } }
注意:难精通+易使用+功能强大的东西,一旦被滥用则后果非常严重
- 缺点1:这种方法是一种方法级别的紧耦合,现实工作中要慎之又慎.
- 缺点2:使可读性下降,debug难度增大.
- 缺点3:把委托回调,异步回调和多线程纠缠在一起,会让代码变得难以阅读和维护.
- 缺点4:委托使用不当有可能造成内存泄漏和程序性能下降.
下面是一段滥用委托的例子:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Operation op1 = new Operation(); Operation op2 = new Operation(); Operation op3 = new Operation(); op3.InnerOperation = op2; op2.InnerOperation = op1; op3.Operate(new object, null, null); //问题1:如果传入的两个参数都为null,失败返回的结果是什么?答:内层操作会调用外层的回调! //问题2:如果传入的两个参数不为null,会出现什么情况?答:所有默认callback都被"穿透性"屏蔽! } } class Operation { public Action DefaultSuccessCallback { get; set; } public Action DefaultFailureCallback { get; set; } public Operation InnerOperation { get; set; } public object Operate(object input,Action successCallback,Action failureCallback) { if (successCallback == null) { successCallback = this.DefaultSuccessCallback; } if (failureCallback == null) { failureCallback = this.DefaultFailureCallback; } object result = null; try { result = this.InnerOperation(input, successCallback, failureCallback); } catch { failureCallback.Invoke(); } successCallback.Invoke(); return result; } } }
委托的高级使用
-
多播委托
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow }; Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green }; Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red }; Action action1 = new Action(stu1.DoHomework); Action action2 = new Action(stu2.DoHomework); Action action3 = new Action(stu3.DoHomework); //单播委托 //action1.Invoke(); //action2.Invoke(); //action3.Invoke(); //多播委托 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 < 5; i++) { Console.ForegroundColor = this.PenColor; Console.WriteLine("Student {0} doing homeword {1} hour(s)",this.ID,i); Thread.Sleep(1000); } } } }
-
隐式异步调用
- 同步与异步简介
- 中英文语言差异
- 同步:你做完了我(在你的基础上)接着做.
- 异步:咱们两个同时做(相当于汉语中的"同步进行")
- 同步调用与异步调用的对比
- 每一个运行的程序是一个进程(process)
- 每一个进程都可以有一个或多个线程(thread)
- 同步调用实在同个线程内
- 异步调用的底层机理是多线程
- 串行==同步==单线程, 并行==异步==多线程
- 隐式多线程VS显示多线程
- 直接同步调用:使用方法名
- 简介同步调用:使用单播/多播委托的invoke方法
- 隐式异步调用:使用委托begininvoke
- 显示异步调用:使用thread或task
- 同步与异步简介
同步直接调用实例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow }; Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green }; Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red }; stu1.DoHomework(); stu2.DoHomework(); stu3.DoHomework(); for (int i = 0; i < 10; i++) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Main thread{0}.", i); Thread.Sleep(1000); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } public void DoHomework() { for (int i = 0; i < 5; i++) { Console.ForegroundColor = this.PenColor; Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i); Thread.Sleep(1000); } } } }
同步单播间接调用实例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow }; Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green }; Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red }; 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 < 10; i++) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Main thread{0}.", i); Thread.Sleep(1000); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } public void DoHomework() { for (int i = 0; i < 5; i++) { Console.ForegroundColor = this.PenColor; Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i); Thread.Sleep(100); } } } }
同步多播间接调用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow }; Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green }; Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red }; Action action1 = new Action(stu1.DoHomework); Action action2 = new Action(stu2.DoHomework); Action action3 = new Action(stu3.DoHomework); action1 += action2; action1 += action3; action1.Invoke(); for (int i = 0; i < 10; i++) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Main thread{0}.", i); Thread.Sleep(1000); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } public void DoHomework() { for (int i = 0; i < 5; i++) { Console.ForegroundColor = this.PenColor; Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i); Thread.Sleep(100); } } } }
隐式异步调用例子:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow }; Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green }; Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red }; Action action1 = new Action(stu1.DoHomework); Action action2 = new Action(stu2.DoHomework); Action action3 = new Action(stu3.DoHomework); action1.BeginInvoke(null, null); action2.BeginInvoke(null, null); action3.BeginInvoke(null, null); for (int i = 0; i < 10; i++) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Main thread{0}.", i); Thread.Sleep(100); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } public void DoHomework() { for (int i = 0; i < 5; i++) { Console.ForegroundColor = this.PenColor; Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i); Thread.Sleep(100); } } } }
显示异步调用1:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow }; Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green }; Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red }; //古老的方式 Thread thread1 = new Thread(new ThreadStart(stu1.DoHomework)); Thread thread2 = new Thread(new ThreadStart(stu2.DoHomework)); Thread thread3 = new Thread(new ThreadStart(stu3.DoHomework)); thread1.Start(); thread2.Start(); thread3.Start(); for (int i = 0; i < 10; i++) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Main thread{0}.", i); Thread.Sleep(100); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } public void DoHomework() { for (int i = 0; i < 5; i++) { Console.ForegroundColor = this.PenColor; Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i); Thread.Sleep(100); } } } }
显示异步调用2:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow }; Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green }; Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red }; Task task1 = new Task(new Action(stu1.DoHomework)); Task task2 = new Task(new Action(stu2.DoHomework)); Task task3 = new Task(new Action(stu3.DoHomework)); task1.Start(); task2.Start(); task3.Start(); for (int i = 0; i < 10; i++) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Main thread{0}.", i); Thread.Sleep(100); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } public void DoHomework() { for (int i = 0; i < 5; i++) { Console.ForegroundColor = this.PenColor; Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i); Thread.Sleep(100); } } } }
- 应该适时地使用接口(interface)取代一些委托的操作
- java完全地使用接口取代了委托的功能.
使用接口取代委托的例子:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo2 { public delegate double Calc(double x, double y); class Program { static void Main(string[] args) { IProductFactory pizzaFactory = new PizzaFactory(); IProductFactory toycarFactory = new ToCarFactory(); WrapFactory wrapFactory = new WrapFactory(); Box box1 = wrapFactory.WraProduct(pizzaFactory); Box box2 = wrapFactory.WraProduct(toycarFactory); Console.WriteLine(box1.product.Name); Console.WriteLine(box2.product.Name); } } interface IProductFactory { Product Make(); } class PizzaFactory : IProductFactory { public Product Make() { Product product = new Product(); product.Name = "Pizza"; return product; } } class ToCarFactory : IProductFactory { public Product Make() { Product product = new Product(); product.Name = "Toy Car"; return product; } } class Product//产品 { public string Name { get; set; } } class Box//包装 { public Product product { get; set; } } class WrapFactory//包装工厂 { public Box WraProduct(IProductFactory productFactory) { Box box = new Box(); Product product = productFactory.Make(); box.product = product; return box; } } class ProductFactory//产品工厂 { public Product MakePizza() { Product product = new Product(); product.Name = "Pizza"; return product; } public Product MakeToCar() { Product product = new Product(); product.Name = "Toy Car"; return product; } } }