委托delegate是函数指针的升级版
一切皆地址
- 变量(数据)是以某个地址为起点的一段内存中所存储的值
- 函数(算法)是以某个地址为起点的一段内存中所存储的一组机器语言命令
直接调用与间接调用
- 直接调用:通过函数名来调用函数,cpu通过函数名直接获取函数所在的地址并开始执行
- 间接调用:通过函数指针来调用函数,cpu通过读取函数指针存储的值获得函数所在的地址并开始执行
委托的意思
说白了就是我把方法交给你,让你替我执行,我不执行。
我想杀个人,但是我不想自己动手,委托给小明,让小明帮我杀这个人。最后人被杀了,我还没有亲自动手就完成了我要做的事。
class Test{public int Add(int a,int b){return a + b;}public int Sub(int a,int b){return a - b;}public void Show(){Console.WriteLine("打印一段话");}}
Action与Func
C#类库自带的委托
static void Main(string[] args){Test test = new Test();test.Show();//这是直接使用//传入一个没有返回值的方法名,可以有参数Action action = new Action(test.Show);//或者这种简写Action action1 = test.Show;action.Invoke();//执行委托action();//简写//泛型,类型是参数类型,最后一个是返回值类型Func<int, int, int> func1 = new Func<int, int, int>(test.Add);Func<int, int, int> func2 = new Func<int, int, int>(test.Sub);//简写Func<int, int, int> func3 = test.Sub;//执行委托int x = func1.Invoke(100, 200);int y = func2(100, 200);Console.WriteLine("{0},{1}",x,y);}
delegate委托最基本的使用
自定义委托是一个类
class Program{static void Main(string[] args){Test test = new Test();//实例化委托对象,传入一个返回类型,参数类型和声明委托一样的方法名Dele dele = new Dele(test.Add);Dele dele1 = new Dele(test.Sub);//使用委托int a = dele.Invoke(100, 200);int b = dele1(200, 200);Console.WriteLine(a);Console.WriteLine(b);}}//声明委托,和类同级public delegate int Dele(int a, int b);
委托的一般使用
模板方法
class Product{public string Name { get; set; }}class Box{public Product Product { get; set; }}class WrapFactory{//传入一个委托类型,这个委托返回一个Product对象public Box WrapProduct(Func<Product> getProduct){Box box = new Box();//执行委托Product product = getProduct.Invoke();box.Product = product;//用委托返回的值赋给box对象的Product属性return box;}}class ProductFactory{//制作披萨public Product MakePizze(){Product product = new Product();product.Name = "披萨";return product;}//制作玩具车public Product MakeToyCar(){Product product = new Product();product.Name = "玩具车";return product;}}
static void Main(string[] args){ProductFactory productFactory = new ProductFactory();//产品工厂WrapFactory wrapFactory = new WrapFactory();//包装工厂//本生产是由工厂来做的,现在工厂不想自己生产,找Func来代工生产Func<Product> func1 = new Func<Product>(productFactory.MakePizze);//委托制作披萨Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);//委托制作玩具车//包装厂需要传入一个代工制作的Func对象Box box1 = wrapFactory.WrapProduct(func1);Box box2 = wrapFactory.WrapProduct(func2);Console.WriteLine(box1.Product.Name);Console.WriteLine(box2.Product.Name);}
回调方法callback
//记录程序的运行状态class Logger{public void Log(Product product){Console.WriteLine("产品:{0}在{1}被创建了,价格是{2}",product.Name,DateTime.UtcNow,product.Price);}}class Product{public string Name { get; set; }public int Price { get; set; }}class Box{public Product Product { get; set; }}class WrapFactory{//传入一个委托类型,这个委托返回一个Product对象public Box WrapProduct(Func<Product> getProduct,Action<Product> logCallback){Box box = new Box();//执行委托Product product = getProduct.Invoke();//如果一个产品的价格大于等于50就调用回调函数记录一下if (product.Price >= 50){logCallback.Invoke(product);}box.Product = product;//用委托返回的值赋给box对象的Product属性return box;}}class ProductFactory{//制作披萨public Product MakePizze(){Product product = new Product();product.Name = "披萨";product.Price = 12;return product;}//制作玩具车public Product MakeToyCar(){Product product = new Product();product.Name = "玩具车";product.Price = 121;return product;}}
static void Main(string[] args){ProductFactory productFactory = new ProductFactory();//产品工厂WrapFactory wrapFactory = new WrapFactory();//包装工厂//本生产是由工厂来做的,现在工厂不想自己生产,找Func来代工生产Func<Product> func1 = new Func<Product>(productFactory.MakePizze);//委托制作披萨Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);//委托制作玩具车Logger logger = new Logger();//声明一个没有返回值的委托,把logger.Log委托给log,要传入的值是Product类型Action<Product> log = new Action<Product>(logger.Log);//包装厂需要传入一个代工制作的Func对象,还有回调函数log记录产品信息Box box1 = wrapFactory.WrapProduct(func1,log);Box box2 = wrapFactory.WrapProduct(func2,log);Console.WriteLine(box1.Product.Name);Console.WriteLine(box2.Product.Name);}
总结
上面的把委托传入方法中。比如传入A方法的委托到B方法里面。其实就是在B方法里面调用A方法。为什么要用委托?和反射一个道理,要在B方法里面调用的方法一定是高度可定制的,就是说可以是A方法,可以是C方法。X方法。写代码时也不知道需要什么方法啊,不能写死,就让使用这个方法的人传一个方法过来,用什么方法你说了算,你把你要用的方法传给我,我调用就是。但是C#好像不能传递方法类型的参数,所以就发明了个委托,带传方法。
单播委托与多播委托
public class Student{public int ID { get; set; }//学生idpublic ConsoleColor PneColor { get; set; }//控制台输出的颜色public Student() { }public Student(int id,ConsoleColor cc){this.ID = id;this.PneColor = cc;}public void DoHomework(){for(int i = 0; i < 2; i++){Console.ForegroundColor = this.PneColor;Console.WriteLine("学生{0}做作业{1}小时",this.ID,i);Thread.Sleep(100);}}}
static void Main(string[] args){Student stu1 = new Student(1,ConsoleColor.Yellow);Student stu2 = new Student(2, ConsoleColor.Green);Student stu3 = new Student(3, ConsoleColor.Red);//学生做作业委托给action来做Action action1 = new Action(stu1.DoHomework);Action action2 = new Action(stu2.DoHomework);Action action3 = new Action(stu3.DoHomework);//一个委托封装一个方法,就是单播委托action1();action2();action3();//一个委托封装多个方法就是多播委托action1 += action2 += action3;action1();}
委托隐式异步调用
static void Main(string[] args){Student stu1 = new Student(1,ConsoleColor.Yellow);Student stu2 = new Student(2, ConsoleColor.Green);Student stu3 = new Student(3, ConsoleColor.Red);//学生做作业委托给action来做Action action1 = new Action(stu1.DoHomework);Action action2 = new Action(stu2.DoHomework);Action action3 = new Action(stu3.DoHomework);//自动生成一个分支线程,第一个参数是回调函数,调用完了这个方法后有什么后续的回调吗,没有就null//第二个参数一般也是nullaction1.BeginInvoke(null,null);action2.BeginInvoke(null, null);action3.BeginInvoke(null, null);}
总结
委托可以用接口代替,面向接口编程
