C#委托
1. 委托是什么?
- 委托(Delegate) 是一种类型,专门用来存储、传递方法。
- 本质上,委托是 方法的容器,可以把方法当作变量一样传递和调用。
- 只要 返回值和参数类型 与委托匹配,就可以存入委托。
委托常用于回调、事件系统、解耦模块逻辑、延迟执行等场景。
2. 使用 delegate 委托的声明(不推荐)
委托的声明语法类似方法声明,只是前面加上 delegate 关键字:
delegate void MyFun(); // 无参无返回值委托声明
delegate int MyFun2(int a); // 有参有返回值委托声明
delegate T MyFun3<T, K>(T v, K k); //泛型委托声明
- 委托可以声明在 命名空间 或 类内部。
- 同一作用域中,委托 不能重名,也不支持重载。
- 委托的本质是类,可以通过实例化调用方法。
3. C#封装好 delegate 的委托(推荐)
Action<T1,...,Tn> action; // 接收 T1~Tn 参数,最多 16 个参数,无返回
Func<T1,...Tn,TResult> func; // 接收 T1~Tn 参数,最多 16 个参数,返回 TResult型值
当想要声明无返回的委托,使用Action。当想要声明有返回的委托,使用Func。
4. 委托的常用
- 委托的声明在方法外 委托的执行在自定义方法里实现,调用自定义方法时会执行委托
- 委托的执行要确认是否为null
- 委托只声明没有实现,委托默认是null,委托的添加或删除在自定义方法里实现,调用自定义方法时会对委托进行添加或删除
4.1 委托常作为类的成员
class Custom
{
public Action<int> action;
public Func<int,int> func;
public void Run()
{
// action 不为空时执行(action 不为null时 也可以使用 action(10)\action.Invoke(10) 执行 推荐使用 ?.Invoke)
action?.Invoke(10);
// func 不为空时执行 (result 结果会等于返回的 num)
int result = func?.Invoke(10);
}
}
class Test
{
int value;
int num = 5;
public void TestMethod()
{
Custom custom = new Custom();
// 通过 lambad 表达式 定义 Custom 类中委托 action 执行内容
custom.action=(a)=>{
value = a;
};
// 通过 lambad 表达式 定义 Custom 类中委托 func 执行内容
custom.func=(a)=>{
value = a;
return num;
};
// 调用 Run 来触发委托
custom.Run();
}
}
4.2. 委托常作为函数参数
class Custom
{
int value = 1;
// 有参无返回方法
public void CustomMethod1(int a)
{
value *= a;
Console.WriteLine("CustomMethod1 value=" + value);
}
//有参有返回方法
public int CustomMethod2(int a)
{
value *= a;
Console.WriteLine("CustomMethod2 value=" + value);
return value;
}
public void Run()
{
Test test = new Test();
// 方法一 传入 已有的方法
test.TestAction(CustomMethod1);
test.TestFunc(CustomMethod2);
// 方法二 传入 Lambda 表达式(推荐)
test.TestAction(a => {
value += a;
});
test.TestFunc(a => {
value += a;
return value;
});
}
}
class Test
{
//传入有参无返回委托
public void TestAction(Action<int> callback)
{
int num = 10;
callback(num); // 调用回调
}
//传入有参有返回委托
public void TestFunc(Func<int,int> callback)
{
int num = 10;
int result = callback(num); // 调用回调
Console.WriteLine("TestFunc result=" + result);
}
}
4.3. 多播委托(Multicast Delegate)
public class Test
{
public void Method1(){}
public void Method2(){}
public void Method3(){}
public int Method11(){ return 0; }
public int Method22(){ return 1; }
public int Method33(){ return 2; }
Action action;
Func<int> func;
//添加委托
public void AddActionFunc()
{
action += Method1;
action += Method2;
action += Method3;
// 按顺序执行添加的方法
action?.Invoke();
func += Method11;
func += Method22;
func += Method33;
// 按顺序执行添加的方法 但是只保留最后一个方法的返回值
int result = func?.Invoke(); // result 结果为2
}
//移除委托(多次移除同一方法不会报错)
public void RemoveActionFunc()
{
action -= Method1;
action -= Method2;
action -= Method3;
func -= Method11;
func -= Method22;
func -= Method33;
}
//清空委托
public void RemoveAllActionFunc()
{
action = null;
func = null;
}
}
5. 委托使用实例
- 怪物死亡后,玩家要加10块钱,界面要更新数据,成就要累加怪物击杀数
class Monster
{
//当怪物死亡时 把自己作为参数传出去
public Action<Monster> deadDoSomething;
//怪物成员变量 特征 价值多少钱
public int money = 10;
public void Die()
{
Console.WriteLine("怪物死亡");
deadDoSomething?.Invoke();
////一般情况下 委托关联的函数 有加 就有减(或者直接清空)
deadDoSomething = null;
}
}
class Player
{
private int myMoney = 0;
public void MonsterDeadDoSomething(Monster m)
{
myMoney += m.money;
Console.WriteLine("现在有{0}元", myMoney);
}
}
class UI
{
private int nowShowMoney = 0;
public void AddCoin(Monster m)
{
nowShowMoney += m.money;
Console.WriteLine("当前面板显示{0}元", nowShowMoney);
}
}
class CJ
{
private int nowKillMonsterNum = 0;
public void AddNum(Monster m)
{
nowKillMonsterNum++;
Console.WriteLine("当前累计击杀怪物{0}个", nowKillMonsterNum);
}
}
class Program
{
static void Main(string[] args)
{
Monster monster = new Monster();
Player player = new Player();
UI panel = new UI();
CJ honor = new CJ();
monster.deadDoSomething += player.MonsterDeadDoSomething;
monster.deadDoSomething += panel.AddCoin;
monster.deadDoSomething += honor.AddNum;
monster.Die();
}
}
在实际项目中,可以把玩家、界面、成就设计为单例类,怪物死亡时,在死亡方法中通过单例实例调用玩家、界面、成就对应方法

浙公网安备 33010602011771号