一、委托的官方文档
C# 中的委托和事件简介 - C# | Microsoft Learn
委托是对具有相同返回类型和参数的方法进行封装,本质上委托也是类,可以跟类一样申明。
委托可以将函数当成参数进行传递。
也可以把委托看成是函数的指针:整数对应使用整数变量指向
二、C#中委托的使用
1、委托的申明
//无参数无返回值
public delegate void RegesterDelegate1();
//有参数无返回值
public delegate void RegesterDelegate2(string str);
//有参数有返回值
public delegate string RegesterDelegate3();
//无参数有返回值
public delegate void RegesterDelegate4(string str);
如果代码需要执行操作,但不知道操作细节,一般可以使用委托。
例如:Thread类之所以知道要在一个新线程里运行申明,唯一的原因就是在启动新线程的时候,向其提供了一个ThreadStart或ParameterizedThreadStart委托实例
Thread newTh = new Thread(Test);
newTh.Start();
public Thread(ThreadStart start);
public delegate void ThreadStart();
//其中,ThreadStart是一个无参无返回值的委托
static void Test()
{
Console.WriteLine("thread test");
}
2、委托的调用
申明委托之后要进行实例化,实例化之后才可以进行调用。
实例化的方式:
方式1:使用new创建委托实例
#传入符合委托返回类型和参数列表的方法 可完成委托的实例化
ShowDelegate showDelegate = new ShowDelegate(test.Show);
方式2:使用赋值的方式
ShowDelegate showDelegate = test.Show;
方式3:匿名委托,要求匿名委托和当前的委托具有同样的返回类型和参数列表
ShowDelegate showDelegate = delegate ()
{
Console.WriteLine("匿名委托");
};
方式4:Lambda表达式
ShowDelegate2 showDelegate2 = (string s, int v) => { Console.WriteLine($"{s}&{v}"); };
showDelegate2("s",2);
调用委托:
1、直接调用;
2、使用invoke();
unity里的综合使用:
使用委托的方式实现一个方法管理脚本,实现脚本间的低耦合
public class MethodsManager : MonoBehaviourSingleton<MethodsManager >//单例
{
//无参数
public delegate void callBack();
Dictionary<string, callBack> AllcallBackfunction = new Dictionary<string, callBack>();
//一个参数
public delegate void callBack_one<T>(T t);
Dictionary<string,callBack_one<System.Action>> AllcallBackfunction_Action=new Dictionary<string, callBack_one<System.Action>>();
#region 注册方法
/// <summary>
/// 重载注册方法 无参数
/// </summary>
/// <param name="A"></param>
public void AttachMethod(callBack A)
{
if (!AllcallBackfunction.ContainsKey(A.Method.Name))
{
Instance.AllcallBackfunction.Add(A.Method.Name, A);
}
else
{
Debug.Log(A.Method.Name + " 方法存在,重命名");
}
}
public void AttachMethod(callBack_one<System.Action> A)
{
if (!AllcallBackfunction_Action.ContainsKey(A.Method.Name))
{
Instance.AllcallBackfunction_Action.Add(A.Method.Name, A);
}
else
{
Debug.Log(A.Method.Name + " 方法存在,重命名");
}
}
#endregion
#region 执行方法
/// <summary>
/// 无参数无返回值调用方法
/// </summary>
/// <param name="key">方法名</param>
public void InvokeMethod(string key)
{
if (AllcallBackfunction.ContainsKey(key))
{
AllcallBackfunction[key].Invoke();
}
else
{
Debug.Log(key + " 方法不存在,重新注册");
}
}
public void InvokeMethod(string key,System.Action parameter)
{
if (AllcallBackfunction_Action.ContainsKey(key))
{
AllcallBackfunction_Action[key].Invoke(parameter);
}
else
{
Debug.Log(key + " 方法不存在,重新注册");
}
}
#endregion
}
调用示例:
public class Test : MonoBehaviour
{
void Start()
{
//Regester private method in ManagerMethods
MethodsManager.Instance.AttachMethod(P_Method);
}
//private method
private void P_Method()
{
Debug.Log("我是P_Method");
}
}
除了方法,还有数据的耦合性,如果两个脚本,脚本A想要访问脚本B的输出数据,一定要进行隔离:
public class DataManager : Singleton<DataManager>
{
public int data1{get;set;}
...
}
DataManager是一个单例,B的输出数据存储到此处,A只要使用DataManager.Instance.data1就能获取到。
这样的写法可以有效的管理功能方法和数据。