C#学习八:委托

什么是委托

  • 委托(delegate)是函数指针的“升级版”
    实例:C/C++中的函数指针
  • 一切皆地址
    变量(数据)是以某个地址为起点的一段内存中所储存的值
    函数(算法)是以某个地址为起点的一段内存中所储存的一组机器语言指令
  • 直接调用与间接调用
    直接调用:通过函数名来调用函数,CPU通过函数名直接获得函数所在地址并开始执行—返回
    间接调用:通过函数指针来调用函数,CPU通过函数指针存储的值获得函数所在地址并开始执行—返回
  • 委托的简单使用
    Action委托
    Func委托
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Calculater calculater = new Calculater();
            Action action = new Action(calculater.Report);
            calculater.Report();//直接调用方法
            action();//间接调用方法


            Func<int, int, int> func = new Func<int, int, int>(calculater.Add);
            Func<int, int, int> func2 = new Func<int, int, int>(calculater.Sub);

            int x=100,y= 200;
            Console.WriteLine(func(x,y));
            Console.WriteLine(func2(x,y));
        }
    }

    class Calculater
    {
        public void Report()
        {
            Console.WriteLine("我一共有三个方法!!");
        }

        public int Add(int a,int b)
        {
            int result = a + b;
            return result;
        }

        public int Sub(int a, int b)
        {
            int result = a - b;
            return result;
        }
    }
}
/*运行结果:我一共有三个方法!!
我一共有三个方法!!
300
-100
 */

委托的声明(自定义委托)

  • 委托是一种类(class),类是数据类型所以委托也是一种数据类型
  • 他的声明方式与一般类不同,主要是为了照顾可读性和C/C++传统
  • 注意声明委托的位置:不要写在其他类的内部
    避免写错地方结果声明成嵌套类型
  • 委托与所封装的方法必须“类型兼容”
    返回值的数据类型一致
    参数列表在个数和数据类型上一致
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 委托的声明
{
    //委托的声明
    public delegate double Calc(double x, double y);
    class Program
    {
        static void Main(string[] args)
        {
            Calculter calculter = new Calculter();
            Calc calc = new Calc(calculter.Add);
            double a = 100, b = 200;
            Console.WriteLine(calc(a,b));
        }
    }
    class Calculter
    {
        public double Add(double a,double b)
        {
            return a + b;
        }
        public double Sub(double a, double b)
        {
            return a - b;
        }
        public double Mull(double a, double b)
        {
            return a * b;
        }
        public double Div(double a, double b)
        {
            return a / b;
        }
    }
}

委托的一般使用

  • 实例:把方法当做参数传给另一个方法
    正确使用一:模板方法,“借用”指定的外部方法来产生结果
    相当于“填空题”
    常位于代码中部
    委托有返回值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 委托的一般使用
{
    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 box = wrapFactory.WrapProduct(func1);
            Box box1 = wrapFactory.WrapProduct(func2);
            Console.WriteLine(box1.Product.Name);
            Console.WriteLine(box.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;
        }
    }
}

正确使用二:回调方法,调用指定的外部方法
相当于“流水线”
常位于代码尾部
委托无返回值

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 委托的一般使用
{
    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);

            Box box = wrapFactory.WrapProduct(func1,log);
            Box box1 = wrapFactory.WrapProduct(func2,log);
            Console.WriteLine(box1.Product.Name);
            Console.WriteLine(box.Product.Name);
        }
    }

    class Logger        //用于记录程序的运行状态
    {
        public void Log(Product product)
        {
            Console.WriteLine("产品{0}创建时间为{1}!",product.Name,DateTime.UtcNow);
        }
    }
    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)           //控制了Log函数的运行
            {
                logCallback(product);
            }
            box.Product = product;
            return box;
        }
    }
    class ProductFactory
    {
        public Product MakePizza()
        {
            Product product = new Product();
            product.Name = "pizza";
            product.price = 12;
            return product;
        }
        public Product MakeToycar()
        {
            Product product = new Product();
            product.Name = "Toycar";
            product.price = 100;
            return product;
        }
    }
}
/*产品Toycar创建时间为2020/4/6 11:00:54!
Toycar
pizza
*/
  • 注意:难精通+易使用+功能强大东西,一旦被滥用后果非常严重
    缺点1:这是一种方法级别的耦合,现实工作中要慎之又慎
    缺点2:使可读性下降、debug的难度增加
    缺点3:把委托回调、异步调用和多线程纠缠在一起,会让代码变得难以阅读和维护
    缺点4:委托使用不当有可能造成内存泄漏和程序性能下降
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值