使用C#,但是大多數時候用不上委托,但是委托被讨論得非常多,于是陷入自我懷疑,我是不是太菜了?
我不禁問:為什麼要使用委托?
可能試圖了解過委托的同學,都被告知委托跟函數指針的關系,又或者被告知一個生活化的舉例:委托就是委托别人執行一件事。
可能很多人嘗試了解委托的時候都停在這一步,他們了解了委托的寫法,尋思:委托也不能簡化寫法,而且做了和函數同樣的事情,為什麼要費勁巴拉的使用委托來間接完成函數調用呢?
想到這,我甚至有點生氣,為什麼他媽的要使用委托?
那就說說為什麼要他媽的使用委托!
當你想把方法當參數傳給另一個方法
-
1. 模闆方法:Reuse,重複使用,也叫“複用”。代碼的複用不但可以提高工作效率,還可以減少 bug 的引入。良好的複用結構是所有優秀軟體所追求的共同目标之一。請仔細品味一下示例程式(示例代碼來自劉鐵錳老師《C#語言入門詳解》系列課程):
class Program
{
static void Main(string[] args)
{
//執行個體化一個ProductFactory,此對象擁有多個成員方法,可被同一種委托類型調用
var productFactory = new ProductFactory();
//定義兩個委托
Func<Product> func1 = new Func<Product>(productFactory.MakePizza);
Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);
var wrapFactory = new WrapFactory();
//将委托類型對象作為參數,傳給裝箱類的構造器
Box box1 = wrapFactory.WrapProduct(func1);
Box box2 = wrapFactory.WrapProduct(func2);
Console.WriteLine(box1.Product.Name);
Console.WriteLine(box2.Product.Name);
}
}
//第一個類:product類,具有一個string類型的屬性Name,描述産品的名稱
class Product
{
public string Name { get; set; }
}
//第二個類:box類,具有一個Product類型的屬性,盒子中有一個product
class Box
{
public Product Product { get; set; }
}
//第三個類:裝箱,構造器接收一個參數,參數為一個委托類型,該委托傳回一個product類型的對象
//将參數傳回的對象,放入box中,完成裝箱
class WrapFactory
{
// 模闆方法,提高複用性
public Box WrapProduct(Func<Product> getProduct)
{
var box = new Box();
Product product = getProduct.Invoke();
box.Product = product;
return box;
}
}
//第四個類:product制造工廠,容納制造各種product的方法,方法數量可依需求擴充
//但特點是傳回值均為Product類型,無參數,即可被同一種委托類型調用
class ProductFactory
{
public Product MakePizza()
{
var product = new Product();
product.Name = "Pizza";
return product;
}
public Product MakeToyCar()
{
var product = new Product();
product.Name = "Toy Car";
return product;
}
}
看完上述程式總結:
我們用了4個類,Product、Box、WrapFactory、ProductFactory,product為操作對象,box為product的裝箱容器,WrapFactory專門執行裝箱操作,ProductFactory容納各種product制造函數,此類為可擴充類,異變更。最終在main方法中,在裝箱時使用委托作為參數,即 wrapFactory.WrapProduct(func1) 這句代碼,我想為什麼不直接wrapFactory.WrapProduct(productFactory.MakePizza),不是更友善嗎?當我繼續往下想,**如果不光是使用參數中的傳回值呢,加入作為參數的方法除了傳回值,還有out類型的輸出參數呢,這時候就不得不使用委托類型作為函數參數了。**而且有沒有莫名覺得上面的示例程式結構非常棒棒,當新增一個種類的Product,指需擴充ProductFactory類的成員,并在main方法中增加一個委托,然後裝箱即可。這就是我們為什麼要使用委托的第一個原因。是以請熟讀并模型示例程式!
-
2. 回調方法:回調方法是通過委托類型參數傳入主調方法的被調用方法,主調方法根據自己的邏輯決定是否調用這個方法。請仔細品味一下示例程式(示例代碼來自劉鐵錳老師《C#語言入門詳解》系列課程):
class Program
{
static void Main(string[] args)
{
var productFactory = new ProductFactory();
// Func 前面是傳入參數,最後一個是傳回值,是以此處以 Product 為傳回值
Func<Product> func1 = new Func<Product>(productFactory.MakePizza);
Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);
var wrapFactory = new WrapFactory();
var logger = new Logger();
// Action 隻有傳入參數,是以此處以 Product 為參數
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)
{
// Now 是帶時區的時間,存儲到資料庫應該用不帶時區的時間 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(Func<Product> getProduct, Action<Product> logCallBack)
{
var box = new Box();
Product product = getProduct.Invoke();
// 隻 log 價格高于 50 的
if (product.Price >= 50)
{
logCallBack(product);
}
box.Product = product;
return box;
}
}
class ProductFactory
{
public Product MakePizza()
{
var product = new Product
{
Name = "Pizza",
Price = 12
};
return product;
}
public Product MakeToyCar()
{
var product = new Product
{
Name = "Toy Car",
Price = 100
};
return product;
}
}