资讯动态

C#委托详解

发布时间:2026/10/23 2:53:34 来源:尧图企业网站定制
什么是委托Action泛型委托Delegate用来封装一个方法且方法不具有参数与返回值Func泛型委托Delegate用来表示一个有返回值的方法尖括号最后一个类型是返回值前面的是参数class Program { static void Main(string[] args) { Calculator calculator new Calculator(); Action action new Action(calculator.Report); calculator.Report(); //直接调用 action(); //间接调用 action.Invoke(); //间接调用同action(); Funcint, int, int func1 new Funcint, int, int(calculator.Add); Funcint, int, int func2 new Funcint, int, int(calculator.Sub); int x 100; int y 200; int z 0; z func1(x, y); //同z func1.Invoke(x, y); Console.WriteLine(z); z func2(x, y); Console.WriteLine(z); } } class Calculator { public void Report() { Console.WriteLine(I hava 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; } }委托的声明自定义委托一般的类声明class 类名 { 类体 }委托的声明放在namespace下是最标准、最清晰的写法放在 类 下则变成嵌套类public delegate double Calc(double x, double y);public-公开访问delegate-关键字告诉编译器我要声明委托了double-目标方法的返回值类型Calc-委托名()-目标方法的参数列表加了括号()代表“立刻执行这个方法并拿到结果”不加括号代表“把这个方法本身当作一个对象传递出去”。Calc calc1 new Calc(calculator.Add);与Calc calc1 new Calc(calculator.Add());使用委托的方法①声明委托②创建委托的实例并将目标方法名称放入委托构造函数的参数列表里③执行委托实例的方法例如Action.Invoke()或者直接用简写Action()则可以通过委托实例的方法来间接调用目标方法namespace ConsoleHelloWorld { 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; c calc1(a, b); Console.WriteLine(c); c calc2(a, b); Console.WriteLine(c); c calc3(a, b); Console.WriteLine(c); c calc4(a, b); Console.WriteLine(c); } } 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然后将该委托当作参数传给方法2②好处简介可以将可能产生变化的业务逻辑部分放在方法1中而方法2当作一个“模板”即模板方法通过固定的委托间接调用方法1这样当业务逻辑需求发生变化时就不用该方法2的代码了而只需要改方法1的代码甚至直接将委托中封装的方法换一个以实现其它功能填空题class Program { static void Main(string[] args) { ProductFactory productFactory new ProductFactory(); //生产产品 WrapFactory wrapFactory new WrapFactory(); //打包产品 FuncProduct func1 new FuncProduct(productFactory.MakePizza); FuncProduct func2 new FuncProduct(productFactory.MakeToyCar); Box box1wrapFactory.WrapProduct(func1); Box box2 wrapFactory.WrapProduct(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 WrapProduct(FuncProduct getProduct) { Box box new Box(); // 1. 先拿个空箱子 Product product getProduct();// 2. 调用委托拿到产品唯一变的填空题的空 box.Product product; // 3. 把产品装进箱子里 return box; // 4. 把装好的箱子交出去 } } class ProductFactory //产品生产厂 { public Product MakePizza() { Product product new Product(); product.Name Pizza; return product; } public Product MakeToyCar() { Product product new Product(); product.Name Toy Car; return product; } }回调方法可以调用也可以不调用用得着的时候就调用用不着就不调用可以动态的选择后续将被调用的方法。如A给B一张名片告诉B有需要可以打电话给A同时又有C、D等也给B名片B可以动态的选择后续需要谁的帮忙。把委托类型的参数传到主调方法里被传进主调方法的委托类型的参数内部会封装被回调的方法主调函数根据自己的逻辑来确认要不要调用回调方法。回调方法常位于主调函数末尾无返回值。namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { ProductFactory productFactory new ProductFactory(); //生产产品 WrapFactory wrapFactory new WrapFactory(); //打包产品 FuncProduct func1 new FuncProduct(productFactory.MakePizza); FuncProduct func2 new FuncProduct(productFactory.MakeToyCar); Logger logger new Logger(); ActionProduct log new ActionProduct(logger.Log); Box box1wrapFactory.WrapProduct(func1,log); Box box2 wrapFactory.WrapProduct(func2, log); Console.WriteLine(box1.Product.Name); Console.WriteLine(box2.Product.Name); } } class Logger //日志 { public void Log(Product product) { //不带时区的UtcNow Console.WriteLine(Product {0} created 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 WrapProduct(FuncProduct getProduct,ActionProduct logCallback) { Box box new Box(); // 1. 先拿个空箱子 Product product getProduct();// 2. 调用委托拿到产品唯一变的填空题的空 if (product.Price 50) { logCallback(product); } box.Product product; // 3. 把产品装进箱子里 return box; // 4. 把装好的箱子交出去 } } class ProductFactory //产品生产厂 { public Product MakePizza() { Product product new Product(); product.Name Pizza; product.Price 12; return product; } public Product MakeToyCar() { Product product new Product(); product.Name Toy Car; product.Price 100; return product; } } }委托的高级使用单播委托1个委托封装1个方法。using System; using System.Threading; namespace ConsoleHelloWorld { 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(); //action.Invoke(); action2(); action3(); } } 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 homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }多播委托1个委托中封装着不止1个方法多播委托在调用的时候它执行的顺序是按照封装方法的先后顺序来执行的using System; using System.Threading; namespace ConsoleHelloWorld { 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(); } } 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 homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }第一个运行起来的线程就是进程的主线程其他线程叫做分支线程。同步调用单线程调用在同一个线程内调用方法时方法的执行时前一个执行完后一个才执行在同一个线程内依次执行的方法调用叫做同步调用直接同步调用using System; using System.Threading; namespace ConsoleHelloWorld { 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 homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }单播委托的间接同步调用using System; using System.Threading; namespace ConsoleHelloWorld { 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(); action3(); 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 homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }多播委托的间接同步调用异步调用多线程调用在不同的线程中去调用方法每个线程跟另外一个线程都互不相干指的是逻辑上互不相干现实工作中经常会遇到多个线程共享同时访问同一个资源比如某个变量的情况 这时候如果处理不当就会产生线程间争夺资源的冲突一个线程的开始和结束并不会影响另一个线程的开始和结束。隐式异步调用begininvoke自动生成分支线程去调用封装的方法using System; using System.Threading; namespace ConsoleHelloWorld { 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(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 homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }主线程与分支线程谁也不等谁同时执行显式异步调用自己动手生成多线程using System; using System.Threading; namespace ConsoleHelloWorld { 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); 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(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 homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleHelloWorld { 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(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 homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }*用类声明一个类类型的属性/字段和用类创建一个类实例的区别是什么本质上是一样的用类创建一个实例赋值左边的就是先声明了一个类类型的变量其实也可以看做是一个字段字段就是一种变量

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑