zoukankan      html  css  js  c++  java
  • 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;
            }
        }
    }
  • 相关阅读:
    固定表头/锁定前几列的代码参考[JS篇]
    盘点mysql中容易被我们误会的地方
    cookie&session的Q&A故事[原理篇]
    网络第一道防线:验证码的故事[安全篇]
    2016,把一年的牛皮先吹了吧[生涯规划篇]
    微软职位内部推荐-Software Engineer II
    微软职位内部推荐-Senior Software Engineer
    微软职位内部推荐-Senior Software Engineer
    微软职位内部推荐-SW Engineer II for Cloud Servi
    微软职位内部推荐-SW Engineer II for Cloud Servi
  • 原文地址:https://www.cnblogs.com/djh5520/p/14680172.html
Copyright © 2011-2022 走看看