起源
在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;
}
}
}
}
View Code
回調方法
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;
}
}
}
}
View Code