C#学习笔记-委托
委托
委托类似于C/C++中的函数指针。委托存储对方法的引用,可以按照某些约束指向目标方法,间接地调用这些方法。
// C
#include<stdio.h>
typedef int (*Calc)(int x, int y);
int Add(int x, int y) {
return x + y;
}
int Sub(int x, int y) {
return x - y;
}
int main() {
int x = 100;
int y = 200;
int res = 0;
Calc funcPoint1 = &Add;
res = funcPoint1(x, y); //间接调用,通过函数指针调用函数
printf("%d + %d = %d\n", x, y, res);
res = Sub(x, y); //直接调用,通过函数名调用函数
printf("%d - %d = %d\n", x, y, res);
}
//C#
class Program
{
static void Main(string[] args)
{
//使用Action委托
Calculator calculator = new Calculator();
Action action = new Action(calculator.Report);
calculator.Report();
action();
//使用Func委托
Func<int, int, int> func1 = new Func<int, int, int>(calculator.Add);
Func<int, int, int> func2 = new Func<int, int, int>(calculator.Sub);
Console.WriteLine(func1(1,2));
Console.WriteLine(func2(1,2));
}
}
class Calculator
{
public void Report()
{
Console.WriteLine("I have 3 methods.");
}
public int Add(int a, int b)
{
return a + b;
}
public int Sub(int a, int b)
{
return a - b;
}
}
委托是一种类,所以委托也是一种数据类型。但是和类的声明方式不同,委托的声明格式更像C/C++中函数指针的声明格式。声明的位置应该在名称空间中(在类中声明,委托会变成嵌套类)。
委托与委托所封装的方法在类型上需要兼容:
1、返回值的数据类型需一致;
2、参数列表的个数和数据类型需一致(参数名可不同);
//自定义委托的声明
public delegate double Calc(double x, double y);
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Calc cal1 = new Calc(calculator.Add);
Calc cal2 = new Calc(calculator.Sub);
Calc cal3 = new Calc(calculator.Mul);
Calc cal4 = new Calc(calculator.Div);
Console.WriteLine(cal1(1.5, 2));
Console.WriteLine(cal2(1.5, 2));
Console.WriteLine(cal3(1.5, 2));
Console.WriteLine(cal4(1.5, 2));
}
}
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;
}
}
委托的一般使用
模板方法,“借用”指定的外部方法来产生结果。
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.MakeToyCar);
Box box1 = wrapFactory.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(Func<Product> getProduct)
{
Box box = new Box();
Product product = getProduct();
box.Product = product;
return box;
}
}
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;
}
}
回调方法是通过委托类型参数传进主调方法的一个被调用方法,主调方法根据情况调用这个方法。
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.MakeToyCar);
Logger logger = new Logger();
Action<Product> log = new Action<Product>(logger.Log);
Box box1 = wrapFactory.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)
{
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(Func<Product> getProduct, Action<Product> logCallBack)
{
Box box = new Box();
Product product = getProduct();
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 MakeToyCar()
{
Product product = new Product();
product.Name = "Toy Car";
product.Price = 100;
return product;
}
}
多播委托
用一个委托封装多个方法。
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 -> action3 -> action 2
action1 += action3;
action1 += action2;
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);
}
}
}
异步调用
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();
Action action1 = new Action(stu1.DoHomeWork);
Action action2 = new Action(stu2.DoHomeWork);
Action action3 = new Action(stu3.DoHomeWork);
//多播委托的间接同步调用
action1 += action2;
action1 += action3;
action1();
//使用委托实现间接异步调用
action1.BeginInvoke(null, null);
action2.BeginInvoke(null, null);
action3.BeginInvoke(null, null);
//显式异步调用
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();
Task task1 = new Task(action1);
Task task2 = new Task(action2);
Task task3 = new Task(action3);
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);
}
}
}
可以使用接口(Interface)取代委托。
class Program
{
static void Main(string[] args)
{
IProductFactory pizzaFactory = new PizzaFactory();
IProductFactory toyCarFactory = new ToyCarFactory();
WrapFactory wrapFactory = new WrapFactory();
Box box1 = wrapFactory.WrapProduct(pizzaFactory);
Box box2 = wrapFactory.WrapProduct(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 ToyCarFactory : 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 WrapProduct(IProductFactory productFactory)
{
Box box = new Box();
Product product = productFactory.Make();
box.Product = product;
return box;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了