C#学习中,随着深入学习,总会遇到委托和事件。但是往往以为理解了,运用时又容易陷入困惑,写不出来了。
为此,我根据我自己的理解与编写思路做了个总结。
首先理解下委托,委托是什么?
我理解委托为:它就是定义了一种函数的类型,凡是与定义的所谓委托具有相同类型的函数,都可以通过委托来进行调用。而所谓函数与委托类型相同,其实就是它们的参数是否相同。
如何使用委托?
1、定义一个委托,或者说是声明委托。这一步就像变量的声明一样,变量也是先声明再赋值,再使用。
格式是:修饰符(public/private) delegate(关键字) void(关键字) 委托名(name) (参数1,参数2...);
例:public delegate void MyHandler();--无参类型的
private delegate void MyHandler(string a);--有参类型的
通常我们定义一个委托把它们定义在类之前,所以我们可以跨类对这个委托使用。尤其我们在定义事件的时候,我们可以根据这种格式的委托,在不同的类中都可以定义事件。
2、定义的与委托参数一样的函数
例:public void DoSomething(){ 函数体... } //无参 public void DoSomething1(){ 函数体... } //无参
public void DoSomething(string b){ 函数体...} //有参
3、实例化委托(相当于绑定要调用的方法)
方法:使用new 关键字
例:使用上面定义的委托和函数 MyHandler AA = new MyHandler(DoSomething); //有参无参的实例化中函数都是只需函数名DoSometing
假如使用匿名方法,那么可以忽略第2步且不需要new关键字,例:MyHandler AA = delegate{函数体...}; //无参
MyHandler AA = delegate(string a){函数体...}; //有参
使用+= 实例化还可依次绑定多个函数方法;
例:MyHandler AA = new MyHandler(DoSomething);
AA += new MyHandler(DoSomething1);
//这样实例化的AA就绑定了两个函数了
例:AA += new
4、委托的调用
使用实例化后的委托调用,调用方法类似于函数的调用。
例:AA(); //无参
AA("字符串"); //有参,带上参数值
除了用delegate定义的委托,还有两个特殊的委托,它们是Action/Func
Action的用法:
相比于delegate,Action是直接忽略了第1步的定义,我们直接实例化,再进行调用就可以了。
Action无参的实例化与调用:
例:Action MyactionHandler = new Action(DoSomething); //无参的实例化
MyactionHandler(); //调用
Action有参的实例化与调用:
实例化格式:Action<参数类型1,参数类型2...> 实例化委托名 = new Action<参数类型1,参数类型2...>(函数名)
例:Action<string> MyactionHandler = new Action<string>(DoSomething); //有参实例化
MyactionHandler("字符串"); //有参调用,带上参数值
Func的用法:
Func跟Action一样,都忽略第1步,也直接实例化然后进行调用,但是Func跟Action的区别是Func必须有返回数值。
Func无参的实例化与调用:
例:Func<string> MyfuncHandler = new Func<string>(DoSomething2); //所定义的第1个参数类型为返回参数类型
public string DoSomething2()
{
return "无参实例化";
}
MyfuncHandler(); //调用
Func有参的实例化与调用:
例:Func<string,string> MyfuncHandler = new Func<string,string>(DoSomething3); //所定义的第1个参数类型为返回参数类型
public string DoSomething3(string aa)
{
return aa;
}
MyfuncHandler("有参实例化"); //调用
Lambda表达式
在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法。 C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式,实际上是委托变得越来越简洁的递进。
使用Lambda表达式是把第2步放在了第3步一起进行实例化,并且简化第3步,用=>取代右侧的“new 委托名”部分。
例:MyHandler AA = (){函数体...}; //无参
MyHandle AA =(x,y){函数体...}; //有参
委托的作用是啥?
我的理解是传递参数或者定义事件。
事件是什么?
事件是基于委托的。我理解的事件是用于传递参数的或者在响应事件时执行命令的。
1、定义事件
结构:修饰符(public/private) event(关键字) 委托名 事件名;//事件是在类中定义的并在类中调用
例:public event MyHandler MyHandlerEvent;
2、订阅事件
方法:事件名 += new 委托名(执行函数的函数名);
事件名 += 执行函数的函数名;//简化
例:MyHandlerEvent += DoSomething;
3、事件的调用
方法:用Invoke或直接调用,跟函数调用方法类似
例:MyHandlerEvent.Invoke(6);
MyHandlerEvent(); //无参
MyHandlerEvent("调用"); //有参
Unity有一个系统自带的委托EventHandler:System.EventHandler.
System.EventHandler是IDE提供的封装好含有2个参数(object sender ,EventArgs e)的委托,前面参数是事件发送者object sender,后面是事件详情标签(传递事件的细节)EventArgs e;
直接用案例来理解:
1、先在一个类中定义事件:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ueventhandler : MonoBehaviour {
public event EventHandler U_HandlerEvent; //定义一个EventHandler事件
//调用方法
//第一个参数为Unity中的一个对象
//后面一个参数表示要传递的参数,类型为EventArgs,自定义也要以它为基类
public void Beginthat(GameObject obj, MyEventArgs e)
{
if (U_HandlerEvent != null)
{
U_HandlerEvent(obj, e);
}
}
}
2、我需要传递参数,所以要自定义一个参数类,可根据需要灵活处理(没有要传递的参数则忽略此步)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyEventArgs : EventArgs
{
private string message;
public string Message { get { return message; } private set { message = value; } }
public MyEventArgs(string _message)
{
Message = _message;
}
}
3、订阅事件与调用事件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class DoSomething : MonoBehaviour {
public Ueventhandler uEventHandler;
// Use this for initialization
void Start () {
uEventHandler.U_HandlerEvent += doSomething;
}
// Update is called once per frame
void Update () {
if(Input.GetMouseButton(0))
{
uEventHandler.Beginthat(gameObject,new MyEventArgs("一些信息"));//没有参数则用EventArgs.Empty
}
}
private void doSomething(object sender,EventArgs e) //这里定义格式是固定的,因为要跟委托类型一致
{
GameObject obj = (GameObject)sender;
MyEventArgs message = (MyEventArgs)e; //强制转换事件信息
Debug.Log("Unity对象:" + obj.name+" "+"传输信息:"+message.Message);
}
}
个人理解,有不足欢迎指正或互相交流学习!
微信交流:wxid_084gqad9geox22