起源
在C语言中,一个函数名代表的是一个地址。比如,创建一个函数int add(int x,int y),此时的函数名add等同于函数地址,调用方法:add(2,4)。这一点没有什么讨论的。
随着typeof的使用,可以使用一个函数指针,typeof int(*P)(int,int),它表示一个函数指针类型,该指针指向两个形参,返回值为int的函数形式。此时P为一个类型,调用它等价于add
比如P p=&add;
p(20,30),相当于等价调用add
——————————————————
看到上面的例子,直觉的想到,能不能把这个函数指针类型放到形参中,这样就可以执行不同的操作。比如:
int Calc(P p,int x,int y){
p(x,y);
}
此时的P是很空泛的概念,只要符合函数指针类型的函数都可以进来,比如加减乘除等各种方法都可以适配,也就是说,用一个方法Calc可以执行各种运算,在这里p可以看作一个方法。在这里,我们看明白了,这些转化的操作就是想把方法放到形参中。
如果我们熟练JS(也可以说是函数式编程语言),JS中函数是一等公民,把函数作为形参是非常平常的事情。(注:关于委托,还会在C++相关笔记中进行记录)
为了记忆方便,提取了重点。
委托类似于指针,可以理解为函数指针的升级版,这是理解委托最关键的地方。
Action和Func
系统自带的两种委托:
- Action
- Func
Action型委托要求委托的目标方法没有返回值,但是可以有形参
Action action=new Action(目标方法);
Func型委托要求委托的目标方法可以带有返回值和形参,形如:
Func<T1,T2,T3> func1=new Func<T1,T2,T3>(目标方法);
* 其中,T1为返回类型,T2、T3表示形参类型
自定义委托delegate的声明
- 委托是一种类(class),类是数据类型所以委托也是一种数据类型
- 它的声名方式与一般的类不同,主要是为了照顾可读性和C/C++传统
- 注意声明委托的位置,避免写错地方结果声明成嵌套类型
- delegate double Calc (double x,double y);
可以与C语言函数指针类比:typedef void(*p)(int,int);
委托的一般使用
实例:把方法当作参数传给另一个方法
- 正确使用:模板方法,“借用”指定的外部方法来产生结果
- 正确使用2:回调方法(callback),调用指定的外部方法
模板方法
结论:
模板方法的作用在于复用。
完整代码:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DelegateExample { 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); } 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.Invoke(); 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 = "ToyCar"; return product; } } } }
回调方法

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DelegateExample { 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); //Log的委托; Box box1 = wrapFactory.WrapProduct(func1, log); Box box2 = wrapFactory.WrapProduct(func2, log); Console.WriteLine(box1.Product.Name); } class Product //产品类 { public string Name { get; set; } public double Price { get; set; } } class Box //盒子类 { public Product Product { get; set; } } class Logger { public void Log(Product product) { Console.WriteLine(product.Price); } } class WrapFactory //包装工厂 { public Box WrapProduct(Func<Product> getProduct, Action<Product> logCallback) { Box box = new Box(); Product product = getProduct.Invoke(); if (product.Price > 50) //如果产品价格大于50,就执行回调方法; { logCallback(product); } box.Product = product; return box; } } class ProductFactory //产品工厂 { public Product MakePizza() { Product product = new Product(); product.Name = "Pizza"; product.Price = 30; return product; } public Product MakeToyCar() { Product product = new Product(); product.Name = "ToyCar"; product.Price = 100; return product; } } } }