随风

    技术2025-10-29  9

    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+"跑了"); } }
    事件和委托的区别和联系
    事件是一种特殊的委托,是委托的一种特殊应用,只能施加"+="(注册事件)"-="(移除事件)操作符,二者本质上是一样的;事件和委托唯一的区别就是:事件不能在类的外部触发,只能在类的内部触发;委托在外部、内部都能触发,但是最好不要在外部触发一个委托。委托常用来表达回调,事件表达外发的接口。
    Processed: 0.009, SQL: 9