Unity/C#------delegation and events (an article to understand thoroughly...)

One: entrust

        All the code language creators are native speakers of English. In the process of translating from English to Chinese, there will inevitably be some words that cannot restore the original meaning. For example, I have never understood constructors and destructors before. I only know these two things The effect is opposite. I didn't fully understand their role until I saw its English meaning, Construstor/Disstructor.

        Next, let's look at entrustment, Delegate, let's look at two example sentences, and understand Delegate in depth...

Can you delegate some tasks or projects? Can you delegate some tasks or projects?

So why not delegate more work to your employees? So why don't you assign more tasks to your employees?

From the above sentence, we can see that it is allocation, which means entrustment (but it feels that some people may not understand entrustment as directly as allocation, at least for me)

Microsoft's official explanation is that a delegate can obtain one or more methods, but the type and return value must be the same as the method. It can be understood that a delegate is an abstraction of a method, that is to say, a template that defines a method. As for how this method looks like , it is implemented by the method itself. This is very similar to a function pointer... I will add this part when I write the unicast delegate later.

We can say that a delegate is a type of method

Not much to say, look at the code...

1. Unicast delegation - only one method can be loaded at a time

Public delegate 返回值 MyDelegate(参数1,参数2)

In this one step, we have defined the delegate, and the next thing to do is to instantiate this thing, so how do we delegate our method?

The first point is that we need to have the same return value and parameter list as the defined delegate type

In fact, delegation is a function pointer that originated in C language, but it exists in the form of delegation in C#

But there is no such thing as a delegate in Java...

//使用Typedef将该函数指针声明为一种类型,它是指向两个参数为int,返回值为int的函数指针
typedef int (*Calculator)(int x , int y);

int Add(int a ,int b)
{
    return a+b;
}

int Multiply(int a ,int b)
{
    return a*b;
}

//函数指针的使用

Calculator Pointer1 = &Add;
Calculator Pointer2 = &Multiply;

//这样我们在调用函数的时候就不再写函数,而是采用函数指针的方法,间接的指向了该类型的函数
Pointer1(0,1);
Pointer2(1,2);

From the above function pointers, we can see that when we register a method, we can indirectly declare a pointer type that is consistent with the method type and return value, so as to call the function pointer, then our delegate is similar to it of....

Next, let's look at the instantiation of our delegate and the insertion of the method. You can use new or directly reference the method:

//实例化委托
MyDelegate myDelegate = new MyDelegate(Function);

//简化写法
myDelegate = Telegate;



返回值类型 Function(参数1,参数2)
{
    方法体;
}

For the call of the delegate, you can use Invoke, or you can directly write the delegate name + ()

可以通过Invoke进行调用委托
myDelegate.Invoke();

也可以直接myDelegate();

2. Multicast delegation - install multiple methods at one time, but it is not safe

In the above method adding link, we only need to make a small modification

myDelegate += ChangeColor;
myDelegate += Log;

But in fact, we have nothing to do and will not do this. In the long run, there may be memory leaks. If one of the methods in the sequential execution list fails, the latter will not be executed, so we have other better options.

3. Action delegation and Func delegation

In most cases, we don't need to declare delegates ourselves, but use ready-made delegates. Unity has built two generic delegates for us.

1) Action delegation - the return value must be empty, and the parameters are optional

//声明无参数的Action委托
Action action;

//声明有参数的Action委托
Action<string,float> action1;

//Action的使用
action = new Action(同参数的方法1)
action1 = new Action<string ,float> (sayhello);

//sayhello方法
public void SayHello(string name,float num)
{
    Debug.log(sting.Fromat("{0} has {1} ChampionShips .",name,num));
}

2) Func delegation - the return value must have, but the parameters are optional

//声明Func委托,前面是参数,后面是返回值
Func<double,double,double> func1;

//使用
func1 = new Func<double,double,double>(Add);


//跟Func结构一样的方法
public double Add(doublea ,double b)
{
    return a+b;
}

Two: Events

Events, enabling objects or classes to be notified

Event is a wrapper for delegated fields, which restricts access to delegated fields

Most of the functions of the delegate instance are hidden from the outside world, and only the function of adding/removing event handlers is exposed

In daily development, there are fewer opportunities to declare events by yourself, and generally there are more existing events...

There is no delegation in java. Events are only implemented with Interface

1. Five important factors of the event

event owner

Event member (Event)

Event Subscriber

Event handler (Event handler, essentially a callback method)

Event subscription (+=)

The relationship between them can be as follows:

1: The owner class of the event and the responder of the event are different classes

using System.Timers;
using UnityEngine;

public class EventTimothyLiu1 : MonoBehaviour
{
    private void Start()
    {
        //世间间隔,每过1s就触发Elesap事件
        Timer timer = new Timer();
        timer.Interval = 1000;

        Boy boy = new();
        Girl girl = new();

        timer.Elapsed += boy.OnAction;
        timer.Elapsed += girl.OnAction;

        timer.Start();
    }
}
public class Boy
{
    internal void OnAction(object sender, ElapsedEventArgs e)
    {
        Debug.Log("1");
    }
}
public class Girl
{
    internal void OnAction(object sender, ElapsedEventArgs e)
    {
        Debug.Log("2");
    }
}

In this example, the owner of the event is the Timer class, and the responder of the event is the custom Boy, Girl class

So the responder and owner of the event are two classes

Second example:

using System;
using System.Windows.Forms;

namespace EventLiu
{
    class Program
    {
        static void Main(string[] args)
        {
            //事件的拥有者:Form
            Form form = new Form();
            //事件的响应者:Controller
            Controller controller = new Controller(form);
            form.ShowDialog();
        }
    }
    class Controller
    {
        private Form form;
        /// <summary>
        /// CTOR再加Tab即可编写出构造器
        /// 也叫构造函数,每个类都必须有
        /// 在构建类的引用时自动运行的方法!
        /// </summary>
        public Controller(Form form)
        {
            if (form!= null)
            {
                //this就是类的实例
                //this后是我们定义的字段,后面是参数form
                this.form = form;
                //Click是事件
                this.form.Click += this.FormClicked;
            }
        }
        /// <summary>
        /// 事件处理器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormClicked(object sender, EventArgs e)
        {
            this.form.Text = DateTime.Now.ToString();
        }
    }
}

In the above code snippet, we introduced the Form namespace

The owner of the event is Form, and the responder of the event is Controller

2: The owner of the event is also the responder of the event

using System;
using System.Windows.Forms;

namespace EventLiu
{
    class Program1
    {
        static void Main(string[] args)
        {
            //事件的拥有者:myForm
            //事件的接受者:myForm
            MyForm myForm = new MyForm();
            //事件:Click
            myForm.Click += myForm.FormClicked;
        }
    }
    /// <summary>
    /// 继承Form
    /// </summary>
    class MyForm : Form
    {
        /// <summary>
        /// 事件的处理器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void FormClicked(object sender, EventArgs e)
        {
            this.Text = DateTime.Now.ToString();
        }
    }
}

The owner of the event is Form

The responder of the event is also an instance of myForm

3: The owner of the event is a member of the responder of the event (highest frequency)

The responder of the event uses its own method to subscribe to the event of its own field members

using System;
using System.Windows.Forms;

namespace EventLiu
{
    class Program1
    {
        static void Main(string[] args)
        {
            MyForm myForm = new MyForm();
            myForm.ShowDIalog();
        }
    }
    class MyForm :Form
    {
        private TextBox textBox;
        //从订阅看事件拥有者就是button
        private Button button;

        public MyForm()
        {
            this.textBox = new TextBox();
            this.button = new Button();
            this.Controls.Add(this.button);
            this.Controls.Add(this.textBox);

            //Click是事件
            //事件的响应者是this,也就是MyForm的实例对象
            this.button.Click += this.ButtonClicked;
        }
        //事件处理器
        private void ButtonClicked(object sender, EventArgs e)
        {
            this.textBox.Text = "Hello";
        }
    }
}

In this code, we create the MyForm class ourselves, inheriting from Form

The owner of the event is the member Button in the class, and the responder of the event is the instantiation of the class

That is, the son has an event, and the father subscribes.                                                                                                                                           

                                                                                                                                                                                                                                                                                 

4: The responder of the event is a member of the owner of the event

2. The complete statement format of the event

Use the following code to see:

using System;
using System.Threading;
using UnityEngine;

public class EventTimothyLiu2 : MonoBehaviour
{
    private void Start()
    {
        Customer1 customer1 = new();
        Waiter1 waiter1 = new();

        customer1.Order += waiter1.Action;
        customer1.Action();
        customer1.PayTheBill();
    }
}
/// <summary>
/// 派生自EventArgs,习惯
/// </summary>
public class OrderEventArgs1:EventArgs
{
    public string DishName { get; set; }
    public string size { get; set; }
}

//把委托放置在类外
/// <summary>
/// 用EvenetHandler原因:
/// 1:别人看到这个后缀就知道这个委托是专门用来声明事件的
/// 2:EventHandle表明委托来约束事件处理器
/// 3:委托的实例是用来存储事件处理器
/// </summary>
/// <param name="customer"></param>
/// <param name="e"></param>
public delegate void OrderEventHandler1(Customer1 customer, OrderEventArgs1 e);


/// <summary>
/// Customer1是事件的拥有者,它拥有事件Order
/// </summary>
public class Customer1
{
    private OrderEventHandler1 OrderEventHandler1;
    public event OrderEventHandler1 Order
    {
        add { this.OrderEventHandler1 += value; }
        remove { this.OrderEventHandler1 -= value; }
    }

    public double Bill { get; set; }

    public void PayTheBill()
    {
        Debug.Log("I will pay $" + this.Bill);
    }

    public void WalkIn()
    {
        Debug.Log("Walk into the restaurant.");
    }
    public void SitDown()
    {
        Debug.Log("Sit down.");
    }
    public void Think()
    {
        for (int i = 0; i < 5; i++)
        {
            Debug.Log("Let me think...");
            Thread.Sleep(1000);
        }
        if(this.OrderEventHandler1 != null)
        {
            OrderEventArgs1 e = new OrderEventArgs1
            {
                DishName = "Kongpao Chicken",
                size = "large"
            };
            this.OrderEventHandler1.Invoke(this,e);
        }
    }
    public void Action()
    {
        this.WalkIn();
        this.SitDown();
        this.Think();
    }
}

/// <summary>
/// Waiter1是事件的接受者,它拥有事件的响应器Action
/// </summary>
public class Waiter1
{
    public void Action(Customer1 customer1, OrderEventArgs1 e)
    {
        Debug.Log("I will serve you  the dish -{0} "+ e.DishName);
        double price = 10;
        switch (e.size)
        {
            case "small":
            price = price * 0.5;
                break;
            case "large":
                price = price * 1.5;
                break;
            default:
                break;
        }
        customer1.Bill += price;
    }
}

As can be seen from the above code

Customer enters the restaurant, walks in, sits down, thinks, and then triggers the order event

Customer is the owner of the order event

Waiter is the receiver of the order event, and it has to respond to the order event, which is to calculate the price and take action

When customizing the ordering event, we use the EventHandler delegate to support the event

The EventArgs class is created to carry the event, whoever initiates the event is the first parameter of the delegate

But it is more complicated to write this way, let's look at the brief declaration format of the event

3. The simple declaration format of the event

using System;
using System.Threading;
using UnityEngine;

public class EventTimothyLiu3 : MonoBehaviour
{
    private void Start()
    {
        Customer2 customer2 = new();
        Waiter2 waiter2 = new Waiter2();

        customer2.Order2 += waiter2.Action;

        customer2.Action();
        customer2.PayTheBill();
    }
}
/// <summary>
/// 先声明委托,委托两个参数分别是事件的拥有者和事件需要使用的参数
/// </summary>
/// <param name="customer2"></param>
/// <param name="e"></param>
public delegate void OrderEventHandler2(Customer2 customer2, OrderEventArgs2 e);

/// <summary>
/// 容纳事件参数
/// </summary>
public class OrderEventArgs2:EventArgs
{
    public string DishName { get; set; }
    public string size { get; set; }
}

/// <summary>
/// 事件的拥有者
/// </summary>
public class Customer2
{
    //原本需要先实例化委托,然后将委托赋予事件中进行使用
    //private OrderEventHandler1 OrderEventHandler1;
    //public event OrderEventHandler1 Order
    //{
    //    add { this.OrderEventHandler1 += value; }
    //    remove { this.OrderEventHandler1 -= value; }
    //}
    //现在进行简化
    /// <summary>
    /// 只需要事件+委托即可
    /// </summary>
    public event OrderEventHandler2 Order2;

    public double Bill { get; set; }
    public void PayTheBill()
    {
        Debug.Log("I will pay $ " + this.Bill);
    }
    public void WalkIn()
    {
        Debug.Log("I'm Coming");
    }
    public void SitDown()
    {
        Debug.Log("I'm sit down");
    }
    public void Think()
    {
        for (int i = 0; i < 5; i++)
        {
            Debug.Log("Let me think..");
            Thread.Sleep(1000);
        }
        if(Order2 != null)
        {
            OrderEventArgs2 e = new OrderEventArgs2();
            e.DishName = "Kongpao Chicken";
            e.size = "large";
            this.Order2.Invoke(this, e);
        }
    }
    public void Action()
    {
        this.WalkIn();
        this.SitDown();
        this.Think();
    }
}
/// <summary>
/// 事件的接收者和Action事件
/// </summary>
public class Waiter2
{
    public void Action(Customer2 customer2, OrderEventArgs2 e)
    {
        Debug.Log("I will serve you  the dish: " + e.DishName);
        double price = 10;
        switch (e.size)
        {
            case "small":
                price = price * 0.5;
                break;
            case "large":
                price = price * 1.5;
                break;
            default:
                break;
        }
        customer2.Bill += price;
    }
}

Still the above code, we simplified

We will code as follows:

private OrderEventHandler1 OrderEventHandler1;
    public event OrderEventHandler1 Order
    {
        add { this.OrderEventHandler1 += value; }
        remove { this.OrderEventHandler1 -= value; }
    }

This simplifies to:

public event OrderEventHandler2 Order2

This simplification is carried out by Microsoft in the background, we can directly write like this

In fact, it is not that the declaration of the entrusted field does not exist. It still exists, but it exists in the background. Microsoft has declared it in the background. We don’t need to see it, so we can simplify it.

It can be further simplified:

Omit the part of declaring the delegate, that is, use the delegate type of EventHandler defined by Microsoft. The code is as follows:

using System;
using System.Threading;
using UnityEngine;

public class EventTimothyLiu4 : MonoBehaviour
{
    private void Start()
    {
        Customer3 customer3 = new Customer3();
        Waiter3 waiter3 = new Waiter3();

        customer3.Order3 += waiter3.Action;

        customer3.Action();
        customer3.PayTheBill();
    }
}
public class OrderEventArgs3:EventArgs
{
    public string DishName { get; set; }
    public string size { get; set; }
}
public class Customer3
{
    public event EventHandler Order3;
    public double Bill { get; set; }

    public void WalkIn()
    {
        Debug.Log("Im coming");
    }
    public void SitDown()
    {
        Debug.Log("Im Sitting");
    }
    public void Think()
    {
        for (int i = 0; i < 5; i++)
        {
            Debug.Log("Im thinking");
            Thread.Sleep(1000);
        }
        if(Order3 != null)
        {
            OrderEventArgs3 e = new OrderEventArgs3();
            e.DishName = "KongpaoChicken";
            e.size = "large";
            this.Order3.Invoke(this, e);
        }
    }
    internal void Action()
    {
        this.WalkIn();
        this.SitDown();
        this.Think();
    }

    internal void PayTheBill()
    {
        Debug.Log("I will Pay for $" + this.Bill);
    }
}
public class Waiter3
{
    public void Action(object sender,EventArgs e)
    {
        Customer3 customer3 = sender as Customer3;
        OrderEventArgs3 orderinfo = e as OrderEventArgs3;

        Debug.Log("i will serve  you the dish" + orderinfo.DishName);
        double price = 10;
        switch (orderinfo.size)
        {
            case "small":
                price = price * 0.5;
                break;
            case "large":
                price = price * 1.5;
                break;
            default:
                break;
        }
        customer3.Bill += price;
    }
}

Note the instantiation of Cutsome3 and OrderEventArgs3 in the Waiter class

Use the method of instantiation and parameter as to convert the parameters into what we need

Why do you need events when you have delegated fields/properties?

In order to make the program logic more reasonable and safer, beware of "killing with a knife"

三:UnityEvent/UnityAction

Supongo que te gusta

Origin blog.csdn.net/leikang111/article/details/129328633
Recomendado
Clasificación