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
原文地址:https://www.cnblogs.com/tinaluo/p/7341729.html