C#高级教程-委托和事件

委托是什么:

委托是一个类型,这个类型可以赋值一个方法的引用。定义一个委托,相当于定义一个类

声明委托:

定义一个委托要定义方法的参数和返回值,使用关键字delegate定义。
delegate void IntMethodInvoker(int x); 有参数无返回值
delegate double TwoLongOp(long first,long second);有参数有返回值
delegate string GetAString();无参数有返回值

使用委托:

private delegate string GetAString();

static void Main(){
int x = 40;
GetAString firstStringMethod = x.ToString;
Console.WriteLine(firstStringMethod()); 调用,现在 firstStringMethod指向了方法x.ToString,指针既视感
}

系统提供的委托:

Action委托和Func委托
Action委托引用了一个void返回类型的方法,T表示方法参数,最多有16个参数。

举例
Action<int,int> 相当于:delegate void INTINT(int,int);

Func引用了一个带有一个返回值的方法,它可以传递0或者多到16个参数类型,和一个返回类型(最后一个参数)
Func<int T1,inT2,in T16,out TResult>

举例:
Func<double,double> 相当于:delegate double DoubleOp(double x);

多播委托:

委托也可以包含多个方法,这种委托叫做多播委托。使用多播委托就可以按照顺序调用多个方法,多播委托只能得到调用的最后一个方法的结果,一般我们把多播委托的返回类型声明为void。

Action action1 = Test1;
action2+=Test2;
action2-=Test1;

注:1.多播委托包含一个逐个调用的委托集合,如果通过委托调用的其中一个方法抛出异常,整个迭代就会停止。
2.多播委托中最好不要null(直接使某个方法=null,例:Test2=null)。可以写空函数,直接return

多播委托的遍历:

Action a1 = Method1;
a1+=Method2;

Delegate[] delegates=a1.GetInvocationList();
foreach(delegate d in delegates){
d.DynamicInvoke(null);
}
遍历多播委托中所有的委托,然后单独调用

匿名方法:

直接在定义完委托之后使用delegate 写函数体(类似Lambda表达式不用写函数名,直接函数体)
例:
Func<int,int,int> plus = delegate (int a,int b){
int temp = a+b;
return temp;
};
int res = plus(34,34);
Console.WriteLine(res);

Lambda表达式:

(参数)=>{函数体} 效果和匿名方法一样
Func<int,int,int> plus = (a,b)=>{ int temp= a+b;return temp; };
int res = plus(34,34);
Console.WriteLine(res);

委托函数 :

普通函数是方法确定,传递参数(实参)(实参不确定,语句确定)
举例:
普通函数调用
在这里插入图片描述

委托函数是参数确定,传递方法(参数已经确定,语句不确定(定义的语句使用形参))
举例1:
带有委托(确定参数,不确定方法,具体情况具体写方法)的函数调用
在这里插入图片描述

使用lambda 表达式写函数的具体实现,(o),(m)是形参,实参在委托函数定义中已经确定
图中的
GetObj 函数实现如下:
public void GetObj(string name, UnityAction callback, UnityAction first){
callback(oneGameobj);
first(twoGameobj);
}
此函数三个参数,后两个参数是委托函数,委托函数确定实参,不确定方法(实参oneGameobj twoGameobj,两个都是GameObject)

举例2:
在这里插入图片描述

1.三个参数,后面两个委托函数,被确定了参数,第二个被确定的参数和第一个相关(可以直接操作第一个参数(见调用实例),第三个参数是游戏物体)
2.UnityAction是unity封装的委托函数,其中<>里面是参数类型,原型中是泛型
3.调用实例
在这里插入图片描述

4.实现效果,调用中让第二个委托打印m(参数一所传递的形参),让第三个委托创造物体(物体是被确定的实参)

在这里插入图片描述

定论:委托函数定义参数 使用方法
定义:
UnityAction<实参类型> 委托1
UnityAction<实参类型> 委托2
委托函数名(委托1,委托2){
委托1(实参);
委托2(实参);
}
调用:
(形参)=>{ 语句(对形参的操作,也可以直接将回调的参数传出来,即外部声明的一个参数=形参,就可以捞出之前委托函数确定的实参,然后可以在别的地方对外部声明的那个参数进行控制=对委托确定的那个实参进行控制) }
举例:效果是将委托中确定的 实参 用外部m捞出,并用m++使得z++,说明委托是传递引用,而不是传递值
public float m
委托函数名((z)=>{m=z});
public void Add(float s){
m++
}

值传递与引用传递

c#没有指针,但是委托和指针的作用类似。
c,c++有指针
值传递,引用传递,输出传递
https://www.runoob.com/csharp/csharp-methods.html

事件:

事件(event)基于委托,为委托提供了一个发布/订阅机制,事件是一种具有特殊签名的委托。
事件(Event)是类或对象向其他类或对象通知发生的事情的一种特殊签名的委托.
事件的声明
public event 委托类型(action,func,delegate定义的Mydelegate) 事件名;
事件使用event关键词来声明,他的返回类值是一个委托类型。
通常事件的命名,以名字+Event 作为他的名称,在编码中尽量使用规范命名,增加代码可读性。

事件的定义在触发的位置,并且在触发时执行委托的事件,比如猫来了这一事件(猫类),然后要添加的函数写在要监听的地方(比如老鼠类)
猫类,猫来了方法执行事件里面的所有委托方法:
在这里插入图片描述

老鼠类,将自身的逃跑方法注册进 猫来了的事件中
在这里插入图片描述

事件与委托用法都是一样的,但是事件不能在外部调用,而委托可以在外部调用
(比如外部调用 注册了很多方法的catCome事件(事件的调用和方法一样:catCome();),实际上调用Catcoming方法也会间接调用catCome事件,但是调用猫来了方法更加合理,因为里面可能还有别的语句需要执行。语句安全问题)
事件可以在外部注册,不能在外部调用,只能在类里调用,可以写一个函数封装事件,从而外部调用事件。
委托可以像方法一样在外部被调用。

posted @ 2020-08-23 22:33  euph  阅读(167)  评论(0编辑  收藏  举报