天天看點

C#重點内容之:委托(delegate)

起源

在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