23考完復變打算更博的,可是那天頂着38.5°C考完復變以後實在頂不住了,歇了幾天算法
委託(delegate)是C/C++裏面函數指針的升級版,若是你有必定的C基礎,那就知道委託的做用了。在計算機裏面一切皆爲地址,變量(數據)是以某個地址爲起點的一段內存中所存儲的值,函數(算法)是以某個地址爲起點的一段內存中所存儲的一組機器語言指令。函數的調用有兩種方法:直接調用和間接調用,直接調用就是直接經過函數的名字來調用,CPU經過函數的名字找到函數存儲的位置進而執行;間接調用是用函數指針來調用,CPU經過函數指針存儲的地址找到函數所在的地方進而執行。
C#中的委託是通過包裝的函數指針,讓你感覺不到它是一個指針。可是實際用起來,就是函數指針的用法。C#中的委託能夠本身寫一個,或者使用C#爲你準備好的一些委託,好比Action
(無返回值的函數)、Func
(有返回值的函數)。
說了這麼多,委託有什麼用呢?拿兩個經典例子來講:模板方法(template method)和回調方法(callback)。
多說無益,看例子:多線程
using System; namespace SomeNote { class Program { static void Main(string[] args) { ProductFactory productFactory = new ProductFactory(); WrapFactory wrapFactory = new WrapFactory(); Box box1 = new Box(); Box box2 = new Box(); Func<Product> fun1 = productFactory.MakePizza; //Func這個委託是C#準備好的,它接受一個帶返回值,可是沒有參數的函數 Func<Product> fun2 = productFactory.MakeToyCar; //Func是一個泛型委託,尖括號裏面是它的返回值類型 box1 = wrapFactory.WrapProduct(fun1); box2 = wrapFactory.WrapProduct(fun2); 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.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 = "Toy Car"; return product; } } }
這就是模板方法,借用指定的外部方法來產生結果。WrapProduct
這個方法是很是好的一個處理方式,你須要什麼就給它什麼,模板方法通常出如今代碼中間。模板方法的委託通常有返回值,放到方法體裏面作各類處理。
程序的執行結果以下:
異步
using System; namespace SomeNote { class Program { static void Main(string[] args) { WrapFactory wrapFactory = new WrapFactory(); ProductFactory productFactory = new ProductFactory(); Box box1 = new Box(); Box box2 = new Box(); Logger logger = new Logger(); Action<Product> action = new Action<Product>(logger.Log); //Action也是C#爲咱們準備好的一個泛型委託 Func<Product> func1 = new Func<Product>(productFactory.MakePizza); //它接收一個沒有返回值,參數只有一個的函數,尖括號裏面是函數的參數類型 Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar); //不知道你有沒有發現這裏聲明委託和上面的例子不同 box1 = wrapFactory.WrapProduct(func1, action); box2 = wrapFactory.WrapProduct(func2, action); Console.WriteLine(box1.Product.Name); Console.WriteLine(box2.Product.Name); } } 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.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 = 60; return product; } public Product MakeToyCar() { Product product = new Product(); product.Name = "Toy Car"; product.Price = 30; return product; } } class Logger //這個類只有一個方法,用來實現回調 { public void Log(Product product) { Console.WriteLine(product.Price); } } }
回調方法的例子我只是在模板方法的基礎上稍做修改。注意到WrapProduct
這個方法多了一個參數,多接收了一個委託。在方法體裏面,多了一個判斷價錢是否大於50,這裏的Action
爲Log
,輸出Product的價格。回調方法至關於一條流水線,你符合就調用,不符合就不調用,它經常位於代碼末,它使用的委託沒有返回值。
最後關注一下1五、1六、17行的代碼,與模板方法的例子不同,這裏委託的聲明一大串,很複雜。這是什麼意思呢?在上一個例子,咱們沒有說明Func
綁定的函數是什麼類型的,這是由於編譯器會幫咱們作推斷。而這個例子咱們把它說清楚了,它就是一個Func<Product>
型的委託,綁定的函數是MakePizza
。其實編譯器很聰明的,通常咱們不用完整說出來它的類型,編譯器會幫咱們推斷。
最終,程序的運行結果:
函數
委託有一個很突出的特色:難精通、易使用、功能強大。委託濫用會產生不少很差的後果:性能
In a word,委託是好東西,可是用以前要三思。spa
由於複習復變,一個星期沒寫碼了。昨天頂着38度作了博客園客製化,侯捷的課還剩下3節。我以爲我挺拼的,可是好像沒什麼結果。下週工做室申請那邊要答辯了,但願一切順順利利吧,爲了R社,也爲了本身。(其實今天這篇博客也是受狒狒啓發才寫的)線程