委托
委托
什么是委托
委托就是 “持有” 一组方法的对象,它类似于C++中的指针,只是C++的指针只能指向一个函数,但是委托可以指向多个函数,因为用委托类型定义的委托对象可以保存多个函数指针,相当于函数指针的升级版。
像Register注册机制和设计模式中的观察者模式和委托一样
一个简单委托的使用例子
void Main()
{
MyClass obj = new MyClass();
obj.ProcEvent();
}
namespace test
{
class MyClass
{
delegate void PressBtn(int btnId); //1、声明一个委托类型
public int derivedVal = 0; //字段
public int Prop //属性
{
get => derivedVal;
set => derivedVal = value;
}
//2、定义自己的函数
private void ProcBtnPress(int id)
{
Console.WriteLine($"Buttton {id} is Pressed");
}
public void ProcEvent()
{
//3、声明一个委托对象,并把自己的函数传进去
PressBtn btnDelagete = new PressBtn(ProcBtnPress);
//4、通过委托对象调用函数
btnDelagete(10);
}
}//class
}//namespace
委托类型的声明
delegate关键字开头,后面跟一个函数的声明,有函数的返回值和签名(函数名和参数)。
这里的函数名即委托类型名,注意委托是引用类型。
delegate void PressBtn(int btnId); //1、声明一个委托类型
委托对象的创建
这里在创建委托对象的同时,传入了我们自定义的ProcBtnPress方法,这个方法会保存到委托对象的方法列表中,并且是第一个(因为在创建委托对象的时候就传入了)
//3、创建一个委托对象,并把自己的函数传进去
PressBtn btnDelagete = new PressBtn(ProcBtnPress);
还可以先声明再保存引用
//声明一个委托对象
PressBtn btnDelagete;
//添加对方法的引用
btnDelagete = new PressBtn(ProcBtnPress);
//还可以直接这样赋值
//这种和上面的使用是等价的,因为在方法名称和相应的委托类型之间存在隐式转换
//PressBtn btnDelagete = ProcBtnPress;
btnDelagete = ProcBtnPress;
由于委托是引用类型,可以通过给他赋值来改变委托对象的引用
//第一个引用
btnDelagete = new PressBtn(ProcBtnPress1);
//第二个引用
//这里重新给委托变量赋值,第一个委托引用对象会被垃圾回收器回收
btnDelagete = new PressBtn(ProcBtnPress2);
添加委托方法
添加给委托对象的方法,它的返回值和签名一定要和定义的委托类型一致
delegate void PressBtn(int btnId); //1、声明一个委托类型
//2、定义自己的函数
private void ProcBtnPress(int id)
{
Console.WriteLine($"Buttton {id} is Pressed");
}
添加给委托的方法即可以类的普通成员方法,也可以是静态方法
组合委托
将多个委托加成一个,
delegate void PressBtn(int btnId); //声明一个委托类型
void Main()
{
MyClass1 obj = new MyClass1();
PressBtn delegate1 = obj.ProcBtnPress;
PressBtn delegate2 = MyClass2.ProcBtnPress;
PressBtn delegate3 = delegate1 + delegate2;
delegate3(20);
}
namespace test
{
class MyClass1
{
public void ProcBtnPress(int id)
{
Console.WriteLine($"MyClass1 Buttton {id} is Pressed");
}
}//class
class MyClass2
{
public static void ProcBtnPress(int id)
{
Console.WriteLine($"MyClass2 Buttton {id} is Pressed");
}
}//class
}//namespace
输出
MyClass1 Buttton 20 is Pressed
MyClass2 Buttton 20 is Pressed
给委托增加和移除方法
委托是恒定不变的,给委托增加和移除方法其实是创建了一个新的委托,新委托是旧委托的副本,只是调用列表变了。
1)增加方法
//使用+=运算符来给委托增加方法
delegate1 += obj.func1;
2)移除方法
移除会从列表的最后一个开始匹配,移除第一个匹配的方法
//使用1=运算符来移除方法
delegate1 -= obj.func1;
//如果不确定委托列表中是否有方法,可以用null来判断
//调用列表为空时,委托会为null
if (delegate1 != null)
{
delegate1 -= obj.func1;
}
调用委托
正常调用时要判断委托列表是否为空,如果列表中没有方法就调用委托,则会报异常
1)像方法一样调用
if (delegate1 != null)
{
delegate1(20);
}
2)使用委托的invoke方法来调用
//这里使用了一个空条件运算符来判断委托是否为空
delegate1?.Invoke(30);
调用带返回值的委托
带返回值的委托在调用时,返回的是最后一个方法的返回值,其他方法的返回值会被忽略
调用带引用参数的委托
如果方法参数含ref引用参数,那么该参数在第一个方法调用后,会被修改,参数修改后的值会传给下一个方法。