C#学习笔记-委托基础

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

namespace Delegate1
{
    // 自定义委托
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Calculator cal = new Calculator();

            // 使用C#中2中最常用的定义的委托类型
            Action actShowMsg = new Action(cal.ShowMessage); // Action委托用于封装不带参数不带返回值的方法(实例/静态)
            // 使用委托间接调用Calculator的ShowMessage方法
            actShowMsg.Invoke();
            // 简便的调用写法,类似函数指针
            actShowMsg();

            Func<int, int, int> funcAdd = new Func<int, int, int>(cal.Add); // Func是一个泛型委托,可以用于封装具有参数和返回值的方法
            Console.WriteLine("88 + 99 = {0}", funcAdd(88, 99));
            Console.WriteLine("88 + 99 = {0}", funcAdd.Invoke(88, 99));


            // 使用自定义委托
            Calc dcal = new Calc(cal.Div);
            Console.WriteLine("150 / 99 = {0}", dcal.Invoke(150, 99));


            ProductFactory prodfac = new ProductFactory();
            WrapFactory wrapfac = new WrapFactory();

            Func<Product> getProdFunc1 = new Func<Product>(prodfac.MakePizza);
            Func<Product> getProdFunc2 = new Func<Product>(prodfac.MakeToyCar);

            Logger logger = new Logger();
            Action<Product> actLog = new Action<Product>(logger.Log);

            Box box1 = wrapfac.WrapProduct(getProdFunc1, actLog);
            Box box2 = wrapfac.WrapProduct(getProdFunc2, actLog);

            Console.WriteLine("Product1 name:{0}", box1.Prod.Name);
            Console.WriteLine("Product2 name:{0}", box2.Prod.Name);
        }
    }

#if false
    1、什么是C#中的委托
        委托是C/C++中函数指针的升级版
    2、一切皆地址
        程序 = 数据 + 算法,
        变量(即用于存储程序中的数据)本质:是以变量名所对应的内存地址为起点的一段内存,在这段内存中所存储的是变量的数据,这段内存的大小则由变量的数据类型决定。(变量名只是一段内存的标识)
        函数(即程序中的算法)本质:       是以函数名名所对应的内存地址为起点的一段内存,在这段内存中所存储的是一组机器语言指令。(函数名也只是一段存储指令的内存的标识)
    3、直接调用和间接调用的本质
        直接调用:直接通过函数名来调用函数,CPU通过函数名直接找到函数所在地址执行里面的机器语言指令,执行完成后返回到调用者。
        间接调用:通过函数指针来调用函数,CPU通过读取函数指针变量中存储的函数起始地址,然后执行地址对应内存里面的机器语言指令,执行完成后返回到调用者。相比于直接调用只是多了一个从函数指针读取函数地址的过程。
    4、自定义委托
        委托也是一种类类型
        委托的声明和一般类的不一样,主要是为了更好的可读性和保留C/C++的传统,类似C++函数指针的声明形式,使用delegate关键字
        注意委托声明的位置,它本身是一种类型,一般声明在名称空间下与其他的类型平级,如果声明在类中则成为嵌套类型。
        委托与封装的方法必须"类型兼容"即返回值、参数列表的类型需要一致
    5、委托的一般使用
        实例:把方法当作参数传给另一个方法,分为模板方法、回调方法2种情形
            模板方法:其他逻辑已经确定,其中有一个步骤依赖委托的结果,一般出现在代码的中间部分
            回调方法:一般位于代码的最后部分,根据一定条件决定委托是否被触发调用
    6、注意
        》委托是一种方法级别的紧耦合
        》使用不当会使可读性下降、debug难度增加
        》如果把委托回调、异步调用和多线程纠缠在一起,会让代码变得难以阅读和维护
        》委托使用不当有可能造成内存泄漏和程序性能下降(因为如果委托了一个实例方法,只要委托引用了这个方法,则这个方法对应的实例就不能释放)
#endif

    class Calculator
    {
        public void ShowMessage()
        {
            Console.WriteLine("This is a simple calculator!");
        }

        public int Add(int lhs, int rhs)
        {
            return lhs + rhs;
        }

        public double Div(double lhs, double rhs)
        {
            return lhs / rhs;
        }
    }

    class Logger
    {
        public void Log(Product prod)
        {
            Console.WriteLine("Product '{0}' created at {1}. Price is {2}", prod.Name, DateTime.UtcNow, prod.Price);
        }
    }

    class Product
    {
        public string Name { get; set; }
        public double Price { get; set; }
    }

    class Box
    {
        public Product Prod { get; set; }
    }

    class WrapFactory
    {
        public Box WrapProduct(Func<Product> getProduct, Action<Product> logCallback)
        {
            Box box = new Box();
            Product prod = getProduct.Invoke(); // 这种情况就是模板方法:其他逻辑已经确定,其中有一个步骤依赖委托的结果,一般出现在代码的中间部分

            if (logCallback != null && prod.Price > 50)
            {
                logCallback(prod); // 这里就是回调方法:一般位于代码的最后部分,根据一定条件决定委托是否被触发调用
            }

            box.Prod = prod;
            return box;
        }
    }

    class ProductFactory
    {
        public Product MakePizza()
        {
            Product prod = new Product() { Name = "Pizza", Price = 12.0 };
            return prod;
        }

        public Product MakeToyCar()
        {
            Product prod = new Product() { Name = "Toy Car", Price = 100.0 };
            return prod;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


// Demo: 使用不当会使可读性下降、debug难度增加
namespace Delegate1
{
    class BadDelegate
    {
        // 使用Operation
        public static void UseOperation()
        {
            Operation op1 = new Operation();
            Operation op2 = new Operation();
            Operation op3 = new Operation();

            // 形成一个操作链
            op3.InnerOperation = op2;
            op2.InnerOperation = op1;

            op3.Operate(new object(), null, null);
            // 问题1:如果传入的2个Action为null,失败和成功的效果是什么?答:内层的操作会调用外层的回调!
            // 问题2:如果传入的2个Action不为null,会出现什么情况?答:所有默认callback会被穿透性屏蔽
        }
    }

    class Operation
    {
        public Action DefaultSuccessCallback { get; set; } // 默认的,操作成功执行的回调
        public Action DefaultFailureCallback { get; set; }
        public Operation InnerOperation { get; set; }  // !!! 

        public object Operate(object input, Action successCallback, Action failureCallback)
        {
            if (successCallback == null)
            {
                successCallback = this.DefaultSuccessCallback;
            }

            if (failureCallback == null)
            {
                failureCallback = this.DefaultFailureCallback;
            }

            object result = null;

            try
            {
                result = this.InnerOperation.Operate(input, successCallback, failureCallback); // !!!
                // Do something later
            }
            catch
            {
                failureCallback.Invoke();
            }

            successCallback.Invoke();

            return result;
        }
    } 
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

/*
 委托高级使用:
    多播委托
    异步调用
     */
namespace Delegate2
{
    class Program
    {
        static void Main(string[] args)
        {
            Work w = new Work();
#if false
            // 多播
            Console.WriteLine("------------------------多播委托--------------------------");       
            Action act = new Action(w.DoWork1);
            act += new Action(w.DoWork2);
            act += new Action(w.DoWork3);
            act.Invoke();
#endif

#if false
            // 委托的异步调用(隐式异步调用,自动在新的线程里面执行)
            Console.WriteLine("------------------------委托异步调用--------------------------");
            Action actRed = new Action(w.DoWork1);
            Action actGreen = new Action(w.DoWork2);
            Action actBlue = new Action(w.DoWork3);
            actRed.BeginInvoke(null, null); // 第一个参数标识委托执行完成后的回调,第二个参数表示传递给回调的参数
            actGreen.BeginInvoke(null, null);
            actBlue.BeginInvoke(null, null);
#endif


#if false
            // 显式异步调用,即显式创建线程
            Thread th1 = new Thread(w.DoWork1);
            Thread th2 = new Thread(w.DoWork2);
            Thread th3 = new Thread(w.DoWork3);
            th1.Start();
            th2.Start();
            th3.Start();

            Task task1 = new Task(new Action(w.DoWork1));
            Task task2 = new Task(new Action(w.DoWork2));
            Task task3 = new Task(new Action(w.DoWork3));
            task1.Start();
            task2.Start();
            task3.Start();
#endif


#if false
            // 使用接口取代委托
            Console.WriteLine("-------------------------接口取代委托实现(多态原理)-------------------------");
            IProductFactory pizzaFac = new PizzaFactory();
            IProductFactory toycarFac = new ToyCarFactory();

            WrapFactory wrap = new WrapFactory();

            Box box1 = wrap.WrapProduct(pizzaFac);
            Box box2 = wrap.WrapProduct(toycarFac);

            Console.WriteLine("Product1:{0}", box1.Prod.Name);
            Console.WriteLine("Product2:{0}", box2.Prod.Name);
#endif

            Console.ReadLine();
        }
    }

    // 多播
    class Work
    {
        public void DoWork1()
        {
            for (int i = 0; i < 5; ++i)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("---Red Work {0}---", i);
                Thread.Sleep(500);
            }
        }

        public void DoWork2()
        {
            for (int i = 0; i < 5; ++i)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("---Green Work {0}---", i + 1);
                Thread.Sleep(500);
            }
        }

        public void DoWork3()
        {
            for (int i = 0; i < 5; ++i)
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.WriteLine("---Blue Work {0}---", i);
                Thread.Sleep(500);
            }
        }
    }


    // *******************************************使用接口来取代委托***********************************************
    interface IProductFactory
    {
        Product Make();
    }

    class PizzaFactory : IProductFactory
    {
        public Product Make()
        {
            Product product = new Product();
            product.Name = "Pizza";
            return product;
        }
    }

    class ToyCarFactory : IProductFactory
    {
        public Product Make()
        {
            Product product = new Product();
            product.Name = "Toy Car";
            return product;
        }
    }

    class Product
    {
        public string Name { get; set; }
    }

    class Box
    {
        public Product Prod { get; set; }
    }

    class WrapFactory
    {
        public Box WrapProduct(IProductFactory prodFactory)
        {
            Box box = new Box();
            Product product = prodFactory.Make(); // 多态
            box.Prod = product;
            return box;
        }
    }
}
原文地址:https://www.cnblogs.com/djh5520/p/14680172.html