C# 委托的一般用法

今天在公司又学习到了一个新的知识点:委托
它相当于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#语言的菜鸟!

  • 7
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
C# 委托是一种类型,它允许将方法作为参数传递给其他方法或存储在变量中。委托常用于事件处理程序、回调函数和多线程编程等场景,以下是 C# 委托用法: 1.定义委托类型 可以使用 `delegate` 关键字定义一个委托类型,例如: ``` delegate void MyDelegate(string message); ``` 上面的代码定义了一个委托类型 `MyDelegate`,它可以引用一个参数为字符串类型、返回值为 void 的方法。 2.创建委托对象 可以使用 `new` 关键字创建一个委托对象,例如: ``` MyDelegate myDelegate = new MyDelegate(MyMethod); ``` 上面的代码创建了一个委托对象 `myDelegate`,它引用方法 `MyMethod`。 3.调用委托对象 可以使用委托对象调用它所引用的方法,例如: ``` myDelegate("Hello, world!"); ``` 上面的代码调用委托对象 `myDelegate` 引用的方法,并传入参数。 4.多播委托 委托可以组合成多个方法的调用,形成一个多播委托。可以使用加法运算符将多个委托组合成一个新的委托,例如: ``` MyDelegate myDelegate1 = new MyDelegate(MyMethod1); MyDelegate myDelegate2 = new MyDelegate(MyMethod2); MyDelegate myDelegate3 = myDelegate1 + myDelegate2; ``` 上面的代码创建了三个委托对象,并将前两个委托对象组合成一个新的委托对象 `myDelegate3`。 5.使用内置委托类型 C# 还提供了一些内置的委托类型,例如 `Func`、`Action`、`Predicate` 等。可以直接使用这些内置委托类型,无需定义新的委托类型。例如: ``` Func<int, int, int> myFunc = (x, y) => x + y; int result = myFunc(1, 2); // result = 3 ``` 上面的代码使用内置委托类型 `Func` 定义了一个接收两个 int 类型参数并返回 int 类型结果的委托对象 `myFunc`,并使用 lambda 表达式实现了方法体。 以上就是 C# 委托的基本用法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpp_learners

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值