C# 委托的一般用法

C# 委托的一般用法今天在公司又学习到了一个新的知识点:委托!它相当于C/C++中的函数指针。也就是间接调用!其实它的作用还是挺大的,但是也是挺难学习的,花了好大的时间才搞懂一点点,但是还是不知道它在项目中该用在什么地方。算了,先不管,先用博客记录下来,也许以后就知道了,就用得上了!!!委托有两种方式:系统封装好的,自定义的。系统封装好的委托系统封装好的委托有很多,这里就主要讲常用的两种:Action和Func.其实这两个很好区别的:Action是没有返回值类型的,所以它只适合0至n个参数的void返回

今天在公司又学习到了一个新的知识点:委托
它相当于C/C++中的函数指针。也就是间接调用!
其实它的作用还是挺大的,但是也是挺难学习的,花了好大的时间才搞懂一点点,但是还是不知道它在项目中该用在什么地方。
算了,先不管,先用博客记录下来,也许以后就知道了,就用得上了!!!

委托有两种方式:系统封装好的,自定义的。


系统封装好的委托

系统封装好的委托有很多,这里就主要讲常用的两种:ActionFunc.

其实这两个很好区别的:

  1. Action是没有返回值类型的,所以它只适合0至n个参数的void返回值的方法。
  2. Func是固定要有一个返回值的,所以它只适合0至n个参数的和带返回值的方法。

Action

定义:Action action = new Action(对象.方法名);

下面我们写一个类来测试一下:

class ActionFuncDelegate { 
   
    public void ADelegate() { 
   
        Console.WriteLine("这是一个返回值为空,参数也为空的函数!");
    }
}

Mian函数:

static void Main(string[] args) { 
   
    ActionFuncDelegate actionDelegate = new ActionFuncDelegate();

    Console.WriteLine("---系统自带委托:Action---");
    // 定义系统的委托:Action
    // 对象.方法名
    Action action = new Action(actionDelegate.ADelegate);
    // 间接调用
    action.Invoke();	// 等效于: action();
    // 直接调用
    actionDelegate.ADelegate();
}

运行截图:
在这里插入图片描述

其他例子:

Action:void返回值,带两个不同的参数。

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

namespace _Action { 
   

    class Program { 
   
        static void Main(string[] args) { 
   

            Action<int, string> action = new Action<int, string>(OutName);

            action.Invoke(5, "Mir.Yang");

            Console.ReadKey();
        }

        static void OutName(int count, string name) { 
   
            for (int i = 0; i < count; i++) { 
   
                Console.WriteLine("Hello {0}.", name);
            }
        }
    }
}

在这里插入图片描述

Func

定义:Func<返回类型, 参数类型1, 参数类型2, 参数类n> func1 = new Func<返回类型, 参数类型1, 参数类型2, 参数类型n>(对象名.方法名);

下面我们写一个类来测试一下:

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

    public int Minus(int a, int b) { 
   
        return a - b;
    }
}

Main函数:

static void Main(string[] args) { 
   
    ActionFuncDelegate actionDelegate = new ActionFuncDelegate();
            
    Console.WriteLine("\n");
    Console.WriteLine("---系统自带委托:Func---");
    // 定义系统的委托:Func
    Func<int, int, int> func1 = new Func<int, int, int>(actionDelegate.Add);
    Func<int, int, int> func2 = new Func<int, int, int>(actionDelegate.Minus);

    int x = 100;
    int y = 200;
    int z = 0;

	// 间接调用
    z = func1.Invoke(x, y);
    Console.WriteLine(z);
    z = func2.Invoke(x, y);
    Console.WriteLine(z);

运行截图:
在这里插入图片描述


自定义委托(delegate)

自定义委托,使用的关键字是:delegate

声明:public delegate 返回类型 委托名(参数1, 参数2,参数n);
例::public delegate double UserD(double x, double y);

当我们需要使用到它时,需要new实例化它才可以使用!

下面我们写一个类来测试一下:

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

namespace Delegate_委托 { 
   

	/************************************************/
    // 声明自定义委托
    public delegate double UserD(double x, double y);

    class UserDelegate { 
   

		// 下面方法返回值都是double类型,且参数都是两个double类型
        public double Add(double x, double y) { 
   
            return x + y;
        }

        public double Min(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;
        }
    }
}

Main函数:

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

namespace Delegate_委托 { 
   
    class Mains { 
   
        static void Main(string[] args) { 
               
            Console.WriteLine("\n");            
            Console.WriteLine("---自定义委托---");
            
            UserDelegate userDelegate = new UserDelegate();
            
            // ***自定义委托***
            // 实例化委托
            UserD userD1 = new UserD(userDelegate.Add);
            UserD userD2 = new UserD(userDelegate.Min);
            UserD userD3 = new UserD(userDelegate.Mul);
            UserD userD4 = new UserD(userDelegate.Div);

            double a = 100;
            double b = 200;
            double c = 0;

			// 间接调用
            c = userD1.Invoke(a, b);
            Console.WriteLine(c);
            c = userD2.Invoke(a, b);
            Console.WriteLine(c);
            c = userD3.Invoke(a, b);
            Console.WriteLine(c);
            c = userD4.Invoke(a, b);
            Console.WriteLine(c);
		}         
    }

}

运行截图:
在这里插入图片描述

当然也可以时其他的不同类型的组合。

委托小例子

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

namespace 委托 { 
   

    // 定义委托
    public delegate void delSayHi(string name);

    class Program { 
   

        static void Main(string[] args) { 
   
            // 方式一 直接调用函数
            Console.WriteLine("--- 方式一 ---");
            SayHiChinese("张三");
            SayHiEnglish("李四");
            Console.WriteLine();


            // 方式二 通过委托调用函数
            Console.WriteLine("--- 方式二 ---");
            delSayHi sayHi1 = new delSayHi(SayHiChinese);
            delSayHi sayHi2 = new delSayHi(SayHiEnglish);

            sayHi1("张三");
            sayHi2("李四");
            Console.WriteLine();


            // 方式三 函数名直接赋值委托调用
            Console.WriteLine("--- 方式三 ---");
            delSayHi sayHi3 = SayHiChinese;
            delSayHi sayHi4 = SayHiEnglish;

            sayHi3("张三");
            sayHi4("李四");
            Console.WriteLine();


            // 方式四 直接将函数名当作参数传给委托调用
            Console.WriteLine("--- 方式四 ---");
            test("张三", SayHiChinese);
            test("李四", SayHiEnglish);
            Console.WriteLine();

            Console.ReadKey();
        }

        // 带有委托参数的函数
        public static void test(string name, delSayHi dsh) { 
   
            dsh(name);
        }


        public static void SayHiChinese(string name) { 
   
            Console.WriteLine("吃饭了吗?" + name);
        }

        public static void SayHiEnglish(string name) { 
   
            Console.WriteLine("Nice to meet you?" + name);
        }
    }
}

运行截图:
在这里插入图片描述


泛型委托

泛型就是相当与C++当中的容器,它可以是任何类型。

代码例子:

寻找数组的最大值(任意类型的数组)

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

namespace 泛型 { 
   

    // 定义泛型委托,实现两数相减
    public delegate int Delegate<T>(T o1, T o2);


    class Program { 
   
        static void Main(string[] args) { 
   
            int[] array1 = { 
    1, 2, 3, 5, 4, 6, 9, 8 };
            string[] array2 = { 
    "asdfasdlg", "xzvcnryt", "waerw4thbvzxt", "asdfgh" };

            // 利用匿名函数实现
            int result1 = GetMax<int>(array1, delegate (int t1, int t2) { 
   
                return t1 - t2;
            });            
            Console.WriteLine("最大值:" + result1);


            string result2 = GetMax<string>(array2, delegate (string s1, string s2) { 
   
                return s1.Length - s2.Length;
            });            
            Console.WriteLine("最大值:" + result2);


            Console.ReadKey();
        }

        // 定义泛型函数
        public static T GetMax<T>(T[] arr, Delegate<T> del) { 
   
            T max = arr[0];

            for (int i = 0; i < arr.Length; i++) { 
   

                // 委托实现max减去arr[i],当小于0,说明max比它小
                if (del(max, arr[i]) < 0) { 
   
                    max = arr[i];
                }
            }

            return max;
        }

    }
}

运行截图:
在这里插入图片描述

其他例子:
实现两个不同类型的变量相加。

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

namespace 复习委托 { 
   

    // 定义泛型委托
    public delegate Y MyDeleAdd<T, Y>(T a, Y b);

    class 泛型委托 { 
   
        static void Main(string[] args) { 
   
            MyDeleAdd<int, double> myDeleAddDouble = new MyDeleAdd<int, double>(DeleAtOne);
            double res = myDeleAddDouble.Invoke(10, 5.5);
            Console.WriteLine("MyDeleAdd<int, double>:{0}", res);

            MyDeleAdd<double, int> myDeleAddInt = new MyDeleAdd<double, int>(DeleteAtTwo);
            int ret = myDeleAddInt.Invoke(10.4, 5);
            Console.WriteLine("MyDeleAdd<double, int>:{0}", ret);

            Console.ReadKey();
        }

        static double DeleAtOne(int x, double y) { 
   
            return x + y;
        }

        static int DeleteAtTwo(double x, int y) { 
   
            return Convert.ToInt32(x + y);  // 转换为int类型,按照四舍五入的原则
        }

    }

}

在这里插入图片描述


委托还有两个常用的用法:模板方法回调方法

模板方法

这个我也不知道该怎么讲,我就把代码放在这里,在讲解一下代码的思路就这样吧!

代码思路:

  1. 我们有一个产品类Product,它包含一个Name属性。
  2. 还有一个箱子类Box,它包含有产品类的对象属性。
  3. 紧接着我们编写一个模板方法类TemplateMethod ,它的返回值是Box类型,参数是Func委托类型,该方法的主要作用是将一个产品包装完后,返回包装后Box的类型。
  4. 我们在定义一个生产产品的工厂类ProductFactory ,里面有生产披萨和玩具卡车的方法。
  5. 这样定义的作用是:我们以后都不需要去修改Product 类 和 Box 类 和 TemplateMethod 类,只是需要后续还有什么商品需要增加的话,就在ProductFactory 类的增加对应的生产方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/* * 委托:模板方法的使用 */

namespace Delegate_委托 { 
   

    // 产品
    class Product { 
   
        public string Name { 
    get; set; }
    }
    
    // 箱子
    class Box { 
   
        public Product product { 
    get; set; }
    }

    // 模板方法(对产品进行包装)
    class TemplateMethod { 
   
        public Box Template(Func<Product> func) { 
   
            Box box = new Box();                // 找一个箱子
            Product product = func.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;
        }
    }
}

Main函数:

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

namespace Delegate_委托 { 
   
    class Mains { 
   
        static void Main(string[] args) { 
   

            Console.WriteLine("\n");
            Console.WriteLine("---委托的常用用法一:模板方法---");
            ProductFactory productFactory = new ProductFactory();   // 产品生产工厂
            TemplateMethod templateMethod = new TemplateMethod();   // 包装产品

            // 定义委托
            Func<Product> f1 = new Func<Product>(productFactory.MakePizza);
            Func<Product> f2 = new Func<Product>(productFactory.MakeToyCar);

            // 产品包装
            Box box1 = templateMethod.Template(f1);
            Box box2 = templateMethod.Template(f2);

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

            Console.WriteLine("\n按任意键继续...");
            Console.ReadKey();
        }
    }

}

运行截图:
在这里插入图片描述


回调方法

按照我个人的理解就是:当函数在正常执行时遇到一些突发状况而调用一个特定的回调方法!

代码还是和上面差不多的代码,就修改一些部分和添加了一个回调方法类Logger 。

产品Product_2 添加多了一个价格Price属性,当包装类TemplateMethod_2 在包装产品时,判断产品的价格大于50元钱时,出发调用回调方法Logger !

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

/* * 委托:回调方法的使用 */

namespace Delegate_委托 { 
   

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

    // 盒子
    class Box_2 { 
   
        public Product_2 product { 
    get; set; }
    }

    /************/
    /* 回调方法 */
    class Logger { 
   
        public void Log(Product_2 product_2) { 
   
            Console.WriteLine("出现价格偏高的产品:产品名字:{0} 产品价格:{1} 出现的时间:{2}", 
                product_2.Name, product_2.Price, DateTime.Now);
        }
    }

    // 模板方法(对产品进行包装)
    class TemplateMethod_2 { 
   
        public Box_2 Template(Func<Product_2> func, Action<Product_2> action) { 
   
            Box_2 box = new Box_2();
            Product_2 product = func.Invoke();

            // 调用回调方法
            if (product.Price > 50) { 
   
                action.Invoke(product);
            }

            box.product = product;

            return box;
        }
    }

    // 生产产品的工厂
    class ProductFactory_2 { 
   
        public Product_2 MakePizza() { 
   
            Product_2 product = new Product_2();
            product.Name = "Pizza";
            product.Price = 15.5;
            return product;
        }

        public Product_2 MakeToyCar() { 
   
            Product_2 product = new Product_2();
            product.Name = "ToyCar";
            product.Price = 55.6;
            return product;
        }
    }
}

Main函数:

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

namespace Delegate_委托 { 
   
    class Mains { 
   
        static void Main(string[] args) { 
   

            Console.WriteLine("\n");
            Console.WriteLine("---委托的常用用法二:回调方法---");
            ProductFactory_2 productFactory_2 = new ProductFactory_2(); // 产品生产工厂
            TemplateMethod_2 templateMethod_2 = new TemplateMethod_2(); // 包装产品
            Logger logger = new Logger();   // 定义回调

            // 定义委托
            Func<Product_2> ff1 = new Func<Product_2>(productFactory_2.MakePizza);
            Func<Product_2> ff2 = new Func<Product_2>(productFactory_2.MakeToyCar);
            Action<Product_2> action_1 = new Action<Product_2>(logger.Log);

            // 产品包装
            // 如果有产品价格高于50,则会调用回调方法
            Box_2 boxs1 = templateMethod_2.Template(ff1, action_1);
            Box_2 boxs2 = templateMethod_2.Template(ff2, action_1);

            Console.WriteLine(boxs1.product.Name);
            Console.WriteLine(boxs2.product.Name);

            Console.WriteLine("\n按任意键继续...");
            Console.ReadKey();
        }
    }

}

运行截图:
在这里插入图片描述


再讲最后一点:
委托有单播委托多播委托两种。

上面我们使用的都是单播委托,所以我们这里就演示多播委托的用法!

多播委托

其实也很简单,就将委托相加起来进行了。
或者定义一个委托,然后将委托对象加等于函数名。

看不懂例子一的可以去看例子二。

下面我们写一个类来测试一下:

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

/* * 多播委托 */

namespace Delegate_委托 { 
   
    class MultiDelegate { 
   
        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 homgwork {1} hour(s)", this.ID, i);
                
                // 睡眠一秒钟
                Thread.Sleep(1000);
            }
        }
    }
}

Main函数:

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

namespace Delegate_委托 { 
   
    class Mains { 
   
        static void Main(string[] args) { 
   

            Console.WriteLine("\n");
            Console.WriteLine("---多播委托---");
            MultiDelegate multicastDelegate1 = new MultiDelegate() { 
    ID = 1, penColor = ConsoleColor.Blue };
            MultiDelegate multicastDelegate2 = new MultiDelegate() { 
    ID = 2, penColor = ConsoleColor.Green };
            MultiDelegate multicastDelegate3 = new MultiDelegate() { 
    ID = 3, penColor = ConsoleColor.Red };

            Action act_1 = new Action(multicastDelegate1.DoHomework);
            Action act_2 = new Action(multicastDelegate2.DoHomework);
            Action act_3 = new Action(multicastDelegate3.DoHomework);

            // 单薄委托测试用例
            /* act_1.Invoke(); act_2.Invoke(); act_3.Invoke(); */


            // 多播委托测试用例
            act_1 += act_2;
            act_1 += act_3;

            act_1.Invoke();

            Console.WriteLine("\n按任意键继续...");
            Console.ReadKey();
        }
    }
}

运行截图:
在这里插入图片描述

多播委托例子二

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

namespace 多播委托 { 
   

    // 定义委托
    public delegate void Del();

    class Program { 
   
        static void Main(string[] args) { 
   

            // 多播委托就是将委托对象+=函数名
            Del del = test1;
            del += test2;
            del += test3;
            del += test4;

            del();

            Console.WriteLine("-----华丽的分割线-----");

            // 有+=,也会有-=
            del -= test2;
            del -= test4;

            del();

            Console.ReadKey();
        }

        public static void test1() { 
   
            Console.WriteLine("测试一");
        }

        public static void test2() { 
   
            Console.WriteLine("测试二");
        }

        public static void test3() { 
   
            Console.WriteLine("测试三");
        }

        public static void test4() { 
   
            Console.WriteLine("测试四");
        }
    }
}

运行截图:
在这里插入图片描述


总结:
好了,委托也就讲到这里了,看懂、看不懂也就凑合一下吧,毕竟我也是一名刚入手C#语言的菜鸟!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/28186.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注