随风_委托浅析

本文深入探讨了C#中的委托和事件概念,包括自定义委托、Action与Func委托、多播委托、Lambda表达式及事件的应用。通过具体示例,如冒泡排序和观察者模式,展示了委托和事件的实际用途。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、什么是委托

如果我们要把方法当做参数来传递的话,就要用到委托。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CSharp_学习委托 : MonoBehaviour
{
    private delegate void MyDelegate(string name);
    // Start is called before the first frame update
    void Start()
    {
        MyDelegate a = new MyDelegate(Method);
        a("HelloWorld!");
    }
    public void Method(string str)
    {
        print(str);
    }
}

2、Action委托和Func委托

  • 除了我们自己定义的委托之外,系统还给我们提供了一个内置的委托类型,Action和Func
using System;
using UnityEngine;
/*
 * Action委托引用了一个Void返回类型的方法,
 * Func委托引用了一个带有返回值的方法
 */
public class CSharp_学习委托 : MonoBehaviour
{
    private void Get()
    {
        print("***");
    }
    private void GetString(string str)
    {
        print(str);
    }
    private void GetInt(int i1,int i2)
    {
        print(i1+i2);
    }
    // Start is called before the first frame update
    void Start()
    {
        //Action可以指向一个没有返回值没有参数的方法
        Action o = Get;
        o();
        //Action可以指向一个没有返回值有一个或多个参数的方法
        Action<string> a = GetString;
        a("HelloWorld!");
        Action<int, int> b = GetInt;
        b(6, 8);

        //Func可以指向一个有返回值没有参数的方法
        Func<int> c = FInt;
        print(c());
        //Func可以指向一个有返回值有一个或多个参数的方法
        Func<int, string> d = FString;
        print(d(3));
        Func<int, int, string> e = FuncString;
        print(e(6, 8));
    }
    private int FInt()
    {
        return 1;
    }
    private string FString(int i)
    {
        return "Hello:"+i;
    }
    private string FuncString(int i1,int i2)
    {
        return ("World:" +( i1 + i2));
    }
}

3、拓展的冒泡排序

using UnityEngine;
using System;
/*
 * 给自定义的类型做排序
 */
public class EmployList : MonoBehaviour
{
    //定义一个排序雇员薪水的方法,参数1:雇员类型的数组  
    //参数2:返回值为bool还有两个Employ参数的Func委托
    static void ComEmp(Employ[] array, Func<Employ, Employ, bool> CompareF)
    {
        for(int i = 0; i < array.Length - 2; i++)
        {
            for(int j = 0; j < array.Length - 1; j++)
            {
                if (CompareF(array[j], array[j + 1])==true)
                {
                    var tem = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = tem;
                }
            }
        }
        foreach (Employ item in array)
        {
            print("名字:" + item.Name + " , " + "薪水:" + item.Salary);
        }
    }
    // Start is called before the first frame update
    void Start()
    {
        //声明一个Employ类型的数组
        Employ[] eArray = new Employ[]
        {
            new Employ("aaa",4500m),
            new Employ("bbb",8300m),
            new Employ("ccc",3700m),
            new Employ("ddd",10500m),
            new Employ("eee",7800m),
        };
        //调用ComEmp方法
        ComEmp(eArray, Employ.Compare);
    }
}
//雇员类,有名字和薪水两种属性
class Employ
{
    private string name;
    private decimal salary;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    public decimal Salary
    {
        get { return salary; }
        set { salary = value; }
    }
    //定义一个有两个参数的构造方法
    public Employ(string name,decimal salary)
    {
        this.Name = name;
        this.Salary = salary;
    }
    //定义一个被Func委托CompareF指定的方法,比较两个对象的薪资的大小
    public static bool Compare(Employ e1, Employ e2)
    {
        if (e1.Salary > e2.Salary)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

4、多播委托

前面使用的委托都只包含一个方法的调用,但是委托也可以包含多个方法,这种委托叫做多播委托。
  • 使用多播委托可以按照顺序调用多个方法;
  • 多播委托只能得到调用的最后一个方法的返回值,因此我们一般把多播委托的返回类型声明为void。
    void A1()
    {
        print("A1");
    }
    void A2()
    {
        print("A2");
    }
    private void Start()
    {
        Action a = A1;
        a += A2;
        a();   //输出a1、a2
        a -= A1;
        //如果a为空会报错
        if (a != null)
        {
            a();   //输出a2
        }
        //取得多播委托中所有方法的委托
        Delegate[] del = a.GetInvocationList();
        del[0].DynamicInvoke();
    }

5、Lambda表达式

相当于匿名方法的简写形式。
    delegate int Del(int i1, int i2);
    private int A2(int i,int f)
    {
        return i + f;
    }
    private void Start()
    {
        //方法一  常规方式
        Del d = new Del(A2); 
        print(d(45, 36));
    }
  • Lambda表达式的参数只有一个时,可以不加括号,当函数体的语句只有一句时,可以不加大括号和return
    private void Start()
    {
        //方法二  使用Lambda表达式  不需要定义A2方法,相当于匿名方法
        //Lambda运算符"=>"左边列出了需要的参数,参数是不需要声明类型的
        Del d = new Del((arg1, arg2) => { return arg1 + arg2; });
        print(d(5, 8));
        Func<int, int> func = i => i * 2;
        print(func(5));
    }

6、事件

  • 事件(enent)基于委托,为委托提供了一个发布/订阅机制,我们可以说事件是一种具有特殊签名的委托。
    //声明一个委托
    public delegate void MyDelegate();
    //事件的声明:public event 委托类型 事件名;
    public event MyDelegate myDelegateEvent;
为方便理解,举个小例子:
  • 观察者设计模式:有一只猫和两只老鼠,当猫叫的时候触发事件(CatShout),然后两只老鼠开始逃跑(MouseRun)。
using System;
using UnityEngine;

public class CSharp_学习委托02 : MonoBehaviour
{
    private void Start()
    {
        //方法一
        //Cat c1 = new Cat("Tom");
        //Mouse m1 = new Mouse("Jie");
        //c1.GetCome += m1.MouseRun;
        //Mouse m2 = new Mouse("Rui");
        //c1.GetCome += m2.MouseRun;
        //c1.CatShout();
        //方法二
        Cat c1 = new Cat("Tom");
        Mouse m1 = new Mouse("Jie",c1);
        Mouse m2 = new Mouse("Rui",c1);
        c1.CatShout();
    }
}
class Cat
{
    public string name;
    public Cat(string str)
    {
        this.name = str;
    }
    public void CatShout()
    {
        Debug.Log("猫"+name+"在叫");
        if (GetCome != null)
            GetCome();
    }
    public event Action GetCome;  //声明一个事件(用来发布消息)
}
class Mouse
{
    public string name;
    //方法一
    //public Mouse(string str)
    //{
    //    this.name = str;
    //}
    //方法二
    public Mouse(string str, Cat cat)
    {
        this.name = str;
        cat.GetCome += this.MouseRun;  //把自身的逃跑方法注册进猫GetCome 事件里面(订阅消息)
    }
    public void MouseRun()
    {
        Debug.Log("老鼠"+name+"跑了");
    }
}
事件和委托的区别和联系
  • 事件是一种特殊的委托,是委托的一种特殊应用,只能施加"+="(注册事件)"-="(移除事件)操作符,二者本质上是一样的;
  • 事件和委托唯一的区别就是:事件不能在类的外部触发,只能在类的内部触发;委托在外部、内部都能触发,但是最好不要在外部触发一个委托。
  • 委托常用来表达回调,事件表达外发的接口。
### IntelliJ IDEA 中通义 AI 功能介绍 IntelliJ IDEA 提供了一系列强大的工具来增强开发体验,其中包括与通义 AI 相关的功能。这些功能可以帮助开发者更高效地编写代并提高生产力。 #### 安装通义插件 为了使用通义的相关特性,在 IntelliJ IDEA 中需要先安装对应的插件: 1. 打开 **Settings/Preferences** 对话框 (Ctrl+Alt+S 或 Cmd+, on macOS)。 2. 导航到 `Plugins` 页面[^1]。 3. 在 Marketplace 中搜索 "通义" 并点击安装按钮。 4. 完成安装后重启 IDE 使更改生效。 #### 配置通义服务 成功安装插件之后,还需要配置通义的服务连接信息以便正常使用其提供的各项能力: - 进入设置中的 `Tools | Qwen Coding Assistant` 菜单项[^2]。 - 填写 API Key 和其他必要的认证参数。 - 测试连接以确认配置无误。 #### 使用通义辅助编程 一旦完成上述准备工作,就可以利用通义来进行智能编支持了。具体操作如下所示: ##### 自动补全代片段 当输入部分语句时,IDE 将自动提示可能的后续逻辑,并允许一键插入完整的实现方案[^3]。 ```java // 输入 while 循环条件前半部分... while (!list.isEmpty()) { // 激活建议列表选择合适的循环体内容 } ``` ##### 解释现有代含义 选中某段复杂的表达式或函数调用,右键菜单里会有选项可以请求通义解析这段代的作用以及优化意见。 ##### 生产测试案例 对于已有的业务逻辑模块,借助于通义能够快速生成单元测试框架及初始断言集,减少手动构建的成本。 ```python def test_addition(): result = add(2, 3) assert result == 5, f"Expected 5 but got {result}" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值