019 委托

实例:C/C++中的函数指针

#include <stdio.h>
#include <stdlib.h>

typedef int(*Calc)(int a, int b);

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

int Sub(int a, int b)
{
    return a-b;
}

int main()
{
    int x = 100;
    int y = 200;
    int z;

    Calc funPiont1 = &Add;
    Calc funPoint2 = &Sub;

    z = funPiont1(x,y);
    printf("%d+%d=%d\n",x,y,z);

    z=funPoint2(x,y);
    printf("%d-%d=%d\n",x,y,z);

    system("pause");
    return 0;
}

C#中的委托:

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

namespace demo2
{
    class Program
    {
        static void Main(string[] args)
        {
            Calcculator calculator = new Calcculator();
            Action action = new Action(calculator.Report);
            calculator.Report();
            action.Invoke();
            action();

            Func<int, int, int> func1 = new Func<int, int, int>(calculator.Add);
            Func<int, int, int> func2 = new Func<int, int, int>(calculator.Sub);
            int x = 20;
            int y = 12;
            int z = func1(x, y);
            Console.WriteLine(z);
            z = func2(x, y);
            Console.WriteLine(z);
        }
    }

    class Calcculator
    {
        public void Report()//报告
        {
            Console.WriteLine("I have 3 methods.");//我有三种方法
        }

        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;
        }
    }
}

C#委托声明(自定义委托)

检测委托是否是一个类(返回结果表示 委托是一个类):

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

namespace demo2
{
    class Program
    {
        static void Main(string[] args)
        {
            Type t = typeof(Action);
            Console.WriteLine(t.IsClass);
        }
    }
}

自己声明一个委托:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Calculator calculator = new Calculator();
            Calc calc1 = new Calc(calculator.Add);
            Calc calc2 = new Calc(calculator.Sub);
            Calc calc3 = new Calc(calculator.Mul);
            Calc calc4 = new Calc(calculator.Div);

            double a = 100;
            double b = 200;
            double c = 0;
            Console.WriteLine(calc1.Invoke(a,b));
            Console.WriteLine(calc2.Invoke(a,b));
            Console.WriteLine(calc3(a,b));
            Console.WriteLine(calc4(a,b));

        }
    }

    class Calculator
    {
        public double Add(double x, double y)
        {
            return x + y;
        }

        public double Sub(double x, double y)
        {
            return x - y;
        }

        public double Mul(double x, double y)
        {
            return x * y;
        }

        public double Div(double x, double y)
        {
            return x / y;
        }

    }
}

 

委托的一般使用

实例:把方法当做参数传给另一个方法

正确使用1:模板方法

  • 相当于填空题
  • 常常位于代码中部
  • 委托有返回值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace demo2
{
    public delegate double Calc(double x, double y);

    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.MakeToCar);

            Box box1 = wrapFactory.WraProduct(func1);
            Box box2 = wrapFactory.WraProduct(func2);

            Console.WriteLine(box1.product.Name);
            Console.WriteLine(box2.product.Name);
        }
    }
    
    class Product//产品
    {
        public string Name { get; set; }
    }

    class Box//包装
    {
        public Product product { get; set; }
    }

    class WrapFactory//包装工厂
    {
        public Box WraProduct(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 MakeToCar()
        {
            Product product = new Product();
            product.Name = "Toy Car";
            return product;
        }
    }
}

 

正确使用2:回调(callback)

  • 相当于流水线
  • 常常位于代码末尾
  • 委托无返回值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace demo2
{
    public delegate double Calc(double x, double y);

    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.MakeToCar);

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

            Box box1 = wrapFactory.WraProduct(func1,log);
            Box box2 = wrapFactory.WraProduct(func2,log);

            Console.WriteLine(box1.product.Name);
            Console.WriteLine(box2.product.Name);
        }
    }

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

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

    class Box//包装
    {
        public Product product { get; set; }
    }

    class WrapFactory//包装工厂
    {
        public Box WraProduct(Func<Product>getProduct,Action<Product>logCallback)
        {
            Box box = new Box();
            Product product = getProduct.Invoke();
            if (product.Price >= 50)
            {
                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 MakeToCar()
        {
            Product product = new Product();
            product.Name = "Toy Car";
            product.Price = 100;
            return product;
        }
    }
}

 

注意:难精通+易使用+功能强大的东西,一旦被滥用则后果非常严重

  • 缺点1:这种方法是一种方法级别的紧耦合,现实工作中要慎之又慎.
  • 缺点2:使可读性下降,debug难度增大.
  • 缺点3:把委托回调,异步回调和多线程纠缠在一起,会让代码变得难以阅读和维护.
  • 缺点4:委托使用不当有可能造成内存泄漏和程序性能下降.

下面是一段滥用委托的例子:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            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:如果传入的两个参数都为null,失败返回的结果是什么?答:内层操作会调用外层的回调!
            //问题2:如果传入的两个参数不为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(input, successCallback, failureCallback);
            }
            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 demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
            Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };
            Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red };

            Action action1 = new Action(stu1.DoHomework);
            Action action2 = new Action(stu2.DoHomework);
            Action action3 = new Action(stu3.DoHomework);

            //单播委托
            //action1.Invoke();
            //action2.Invoke();
            //action3.Invoke();

            //多播委托
            action1 += action2;
            action1 += action3;

            action1.Invoke();
        }
    }

    class Student
    {
        public int ID { get; set; }
        public ConsoleColor PenColor { get; set; }

        public void DoHomework()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homeword {1} hour(s)",this.ID,i);
                Thread.Sleep(1000);
            }
        }
    }
}
  • 隐式异步调用

    • 同步与异步简介
      • 中英文语言差异
      • 同步:你做完了我(在你的基础上)接着做.
      • 异步:咱们两个同时做(相当于汉语中的"同步进行")
    • 同步调用与异步调用的对比
      • 每一个运行的程序是一个进程(process)
      • 每一个进程都可以有一个或多个线程(thread)
      • 同步调用实在同个线程内
      • 异步调用的底层机理是多线程
      • 串行==同步==单线程, 并行==异步==多线程
    • 隐式多线程VS显示多线程
      • 直接同步调用:使用方法名
      • 简介同步调用:使用单播/多播委托的invoke方法
      • 隐式异步调用:使用委托begininvoke
      • 显示异步调用:使用thread或task

同步直接调用实例:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
            Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };
            Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red };

            stu1.DoHomework();
            stu2.DoHomework();
            stu3.DoHomework();

            for (int i = 0; i < 10; i++)
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Main thread{0}.", i);
                Thread.Sleep(1000);
            }
        }
    }

    class Student
    {
        public int ID { get; set; }
        public ConsoleColor PenColor { get; set; }

        public void DoHomework()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i);
                Thread.Sleep(1000);
            }
        }
    }
}

同步单播间接调用实例:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
            Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };
            Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red };

            Action action1 = new Action(stu1.DoHomework);
            Action action2 = new Action(stu2.DoHomework);
            Action action3 = new Action(stu3.DoHomework);

            action1.Invoke();
            action2.Invoke();
            action3.Invoke();

            for (int i = 0; i < 10; i++)
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Main thread{0}.", i);
                Thread.Sleep(1000);
            }
        }
    }

    class Student
    {
        public int ID { get; set; }
        public ConsoleColor PenColor { get; set; }

        public void DoHomework()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i);
                Thread.Sleep(100);
            }
        }
    }
}

同步多播间接调用:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
            Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };
            Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red };

            Action action1 = new Action(stu1.DoHomework);
            Action action2 = new Action(stu2.DoHomework);
            Action action3 = new Action(stu3.DoHomework);

            action1 += action2;
            action1 += action3;

            action1.Invoke();

            for (int i = 0; i < 10; i++)
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Main thread{0}.", i);
                Thread.Sleep(1000);
            }
        }
    }

    class Student
    {
        public int ID { get; set; }
        public ConsoleColor PenColor { get; set; }

        public void DoHomework()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i);
                Thread.Sleep(100);
            }
        }
    }
}

隐式异步调用例子:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
            Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };
            Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red };

            Action action1 = new Action(stu1.DoHomework);
            Action action2 = new Action(stu2.DoHomework);
            Action action3 = new Action(stu3.DoHomework);

            action1.BeginInvoke(null, null);
            action2.BeginInvoke(null, null);
            action3.BeginInvoke(null, null);

            for (int i = 0; i < 10; i++)
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Main thread{0}.", i);
                Thread.Sleep(100);
            }
        }
    }

    class Student
    {
        public int ID { get; set; }
        public ConsoleColor PenColor { get; set; }

        public void DoHomework()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i);
                Thread.Sleep(100);
            }
        }
    }
}

显示异步调用1:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
            Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };
            Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red };

            //古老的方式
            Thread thread1 = new Thread(new ThreadStart(stu1.DoHomework));
            Thread thread2 = new Thread(new ThreadStart(stu2.DoHomework));
            Thread thread3 = new Thread(new ThreadStart(stu3.DoHomework));

            thread1.Start();
            thread2.Start();
            thread3.Start();

            for (int i = 0; i < 10; i++)
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Main thread{0}.", i);
                Thread.Sleep(100);
            }
        }
    }

    class Student
    {
        public int ID { get; set; }
        public ConsoleColor PenColor { get; set; }

        public void DoHomework()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i);
                Thread.Sleep(100);
            }
        }
    }
}

显示异步调用2:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
            Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };
            Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red };

            Task task1 = new Task(new Action(stu1.DoHomework));
            Task task2 = new Task(new Action(stu2.DoHomework));
            Task task3 = new Task(new Action(stu3.DoHomework));

            task1.Start();
            task2.Start();
            task3.Start();

            for (int i = 0; i < 10; i++)
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Main thread{0}.", i);
                Thread.Sleep(100);
            }
        }
    }

    class Student
    {
        public int ID { get; set; }
        public ConsoleColor PenColor { get; set; }

        public void DoHomework()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homeword {1} hour(s)", this.ID, i);
                Thread.Sleep(100);
            }
        }
    }
}
  •  应该适时地使用接口(interface)取代一些委托的操作
    • java完全地使用接口取代了委托的功能.

使用接口取代委托的例子:

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

namespace demo2
{
    public delegate double Calc(double x, double y);

    class Program
    {
        static void Main(string[] args)
        {
            IProductFactory pizzaFactory = new PizzaFactory();
            IProductFactory toycarFactory = new ToCarFactory();
            WrapFactory wrapFactory = new WrapFactory();
 
            Box box1 = wrapFactory.WraProduct(pizzaFactory);
            Box box2 = wrapFactory.WraProduct(toycarFactory);

            Console.WriteLine(box1.product.Name);
            Console.WriteLine(box2.product.Name);
        }
    }

    interface IProductFactory
    {
        Product Make();
    }

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

    class ToCarFactory : 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 product { get; set; }
    }

    class WrapFactory//包装工厂
    {
        public Box WraProduct(IProductFactory productFactory)
        {
            Box box = new Box();
            Product product = productFactory.Make();
            box.product = product;
            return box;
        }
    }

    class ProductFactory//产品工厂
    {
        public Product MakePizza()
        {
            Product product = new Product();
            product.Name = "Pizza";
            return product;
        }

        public Product MakeToCar()
        {
            Product product = new Product();
            product.Name = "Toy Car";
            return product;
        }
    }
}

 

posted @ 2018-11-01 15:10  不夜君  阅读(516)  评论(0编辑  收藏  举报