【C# 初学16】

【C# 初学16】,第1张

C#委托学习笔记

C#委托小记
  • 一、什么是委托
  • 二、委托的声明(自定义委托)
  • 三、委托的一般使用
  • 四、委托的高级使用
  • 建议


一、什么是委托
  • 委托(delegate)是函数指针的升级版
  • 一切皆地址
    • 变量(数据)是以某个地址为起点的一段内存中所存储的值
    • 函数(算法)是以某个地址为起点的一段内存中所存储的一组机器语言指令
  • 直接调用与间接调用
    • 直接调用:通过函数名来调用函数,CPU通过函数名直接获得所在地址并开始执行->返回
    • 间接调用:通过函数指针来调用函数,CPU通过读取函数指针存储的值获取函数所在地址并开始执行->返回
  • Java中没有与委托相对应的功能实体
  • 委托的简单使用
    • Action委托
 static void Main(string[] args)
        {
            Calcauator calcauator = new Calcauator();
            Action action = new Action(calcauator.Report);//Report后没有(),在这里只需要方法名,加()表明想要调用这个方法
            calcauator.Report();
            action.Invoke();//委托.Invoke 方法
            action();//也可以直接调用委托
        }
        class Calcauator
        {
            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;
            }

        }
  • Func委托
 static void Main(string[] args)
        {
            Calcauator calcauator = new Calcauator();
            Action action = new Action(calcauator.Report);//Report后没有(),在这里只需要方法名,加()表明想要调用这个方法
            calcauator.Report();
            action.Invoke();//委托.Invoke 方法
            action();//也可以直接调用委托

            //Func委托
            Func<int, int, int> func1 = new Func<int, int, int>(calcauator.Add);
            Func<int, int, int> func2 = new Func<int, int, int>(calcauator.Sub);

            int x = 100;
            int y = 200;
            int z = 0;
            //写法1
            //z = func1.Invoke(x,y);
            //Console.WriteLine(z);
            //z = func2.Invoke(x, y);
            //Console.WriteLine(z);

            //写法2
            z = func1(x, y);
            Console.WriteLine(z);
            z = func2(x, y);
            Console.WriteLine(z);
        }
    }
        class Calcauator
        {
            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/C++传统
  • 注意声明委托的位置

    namespace While
{

    //声明委托
    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;

            //写法1
            //c = calc1.Invoke(a,b);
            //Console.WriteLine(c);
            //c = calc2.Invoke(a, b);
            //Console.WriteLine(c);
            //c = calc3.Invoke(a, b);
            //Console.WriteLine(c);
            //c = calc4.Invoke(a, b);
            //Console.WriteLine(c);

            //写法2
            c = calc1(a, b);
            Console.WriteLine(c);
            c = calc2(a, b);
            Console.WriteLine(c);
            c = calc3(a, b);
            Console.WriteLine(c);
            c = calc4(a, b);
            Console.WriteLine(c);
        }
    }
    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:模板方法,“借用”指定的外部方法来产生结果
      1. 相当于“填空题”
      2. 常位于代码中部
      3. 委托有返回值
 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);
            Console.WriteLine(box2.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();//获取一个Box
            Product product = getProduct.Invoke();//获取一个产品
            box.Product = product;//将产品装到box里面
            return box; //最后返回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;
        }
    }
  • 正确使用2:回调(callback)方法 ,调用指定的外部方法,也叫好莱坞方法
    1.相当于“流水线”
    2. 常位于代码末尾
    3. 委托无返回值

对于没有返回值的方法使用Action委托

 class Program
    {
        static void Main(string[] args)
        {
            ProductFactory productFactory = new ProductFactory();
            WrapFactory wrapFactory = new WrapFactory();
            Logger logger = new Logger();
            Action<Product> log = new Action<Product>(logger.Log);

            Func<Product> func1 = new Func<Product>(productFactory.MakePizza);
            Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);

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

    class Logger //程序记录
    {
       public void Log(Product product)
        {
            Console.WriteLine("Product{0} creat 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 WrapProduct(Func<Product>getProduct,Action<Product>logCallBack)//Func模板方法,Action展示回调方法了
        {
            Box box = new Box();//获取一个Box
            Product product = getProduct.Invoke();//获取一个产品
            if (product.Price>=50)
            {
                logCallBack(product);
            }

            box.Product = product;//将产品装到box里面
            return box; //最后返回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;
        }
    }
四、委托的高级使用
  • 多播(multicast)委托:一个委托内部封装了不止一个方法
 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 Homework{1}Hour(s)",this.ID,i);
                Thread.Sleep(1000);//线程睡1秒钟
            }
        }
    }
  • 隐式异步调用
    • 异步:咱们两个同时做,相当于汉语中的同步进行
    • 同步:你做完了我(在你的基础上)接着做

同步调用指的是在单线程里串行调用,异步调用指的是多线程并行调用

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(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 Homework{1}Hour(s)",this.ID,i);
                Thread.Sleep(1000);//线程睡1秒钟
            }
        }
    }
  • 显式异步调用
 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);

            显式异步调用,方式一
            //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();

            //显式异步调用,方式二

            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(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 Homework{1}Hour(s)",this.ID,i);
                Thread.Sleep(1000);//线程睡1秒钟
            }
        }
    }
建议

应当适时的使用接口(interface)取代一些对委托的使用

class Program
    {
        static void Main(string[] args)
        {
            IProductFactory pizzafactory = new PizzaFactory();
            IProductFactory toycarfactory = new ToyCarFactory();

            WrapFactory wrapFactory = new WrapFactory();

            Box box1 = wrapFactory.WrapProduct(pizzafactory);
            Box box2 = wrapFactory.WrapProduct(toycarfactory);
            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 WrapProduct(IProductFactory productFactory)
        {
            Box box = new Box();
            Product product = productFactory.Make();
            box.Product = product;
            return box;
        }
    }
    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 = "ToyCar";
            return product;
        }
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/721154.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存