Detailed explanation of delegate event and callback function in C

  • 2021-11-14 06:53:37
  • OfStack

Events must be one of the most frequently used elements in Net programming. Whether in ASP. NET or WINFrom development, form loading (Load), drawing (Paint), initialization (Init), and so on.

I believe no one is unfamiliar with the code "protected void Page_Load (object sender, EventArgs e)". Careful 1: 1 will find that many event methods take two parameters: "object sender, EventArgs e". Is this very similar to delegation?

1. Delegation (also called delegation in some books)

What is the entrustment? The meaning of this name has given us room to imagine. You are programming. You are writing an ASP. NET web page, but JS is unfamiliar to you, so you entrust a colleague to help you complete JS. This is entrustment, giving others what you can't do. And how do you know who did it? Of course, you need to know the name! In order to distinguish different people with 1 name, it is necessary to describe 1 feature.

In C #, the role of a delegate is described as follows: Delegates are like pointers to a function that can be used to call different functions while the program is running. This is actually the same as the JS code 1 that you entrusted your colleagues to complete. If there are two colleagues who can do this, they only need to do the result that can meet your needs (just like an interface). Although they do different processes and make different effects, they can meet your requirements.

1. Simple Delegation

What information does the delegate need to carry? First, it stores the method name, along with the parameter list (method signature), and the type returned. For example:

delegate string/* Return Type*/ProcessDelegate (int i);

This is the definition of a delegate. The blue part is the keyword that declares the delegate, the red part is the returned type, the black part is the delegate's type name, which is similar to a class name, and the parameter part in () is the parameter part. It means that if you want to use this delegate to do something, then the method of doing something must meet the following conditions:

1. Return type and delegate return type 1, here string type;

2. Can and can only have 1 parameter and is of int type.

OK, if the above two conditions are met, it can work with 1 cut:)

For example:


using System;
 using System.Collections.Generic;
 using System.Text; 
 namespace TestApp
 {
   /// <summary>
  ///  Delegate 
   /// </summary>
   /// <param name="s1"></param>
   /// <param name="s2"></param>
   /// <returns></returns>
   public delegate string ProcessDelegate(string s1, string s2);
 
   class Program
   {
     static void Main(string[] args)
     {
       /*  Invoke method  */
       ProcessDelegate pd = new ProcessDelegate(new Test().Process);
       Console.WriteLine(pd("Text1", "Text2"));
     }
   }
 
   public class Test
   {
     /// <summary>
     ///  Method 
     /// </summary>
     /// <param name="s1"></param>
     /// <param name="s2"></param>
     /// <returns></returns>
     public string Process(string s1,string s2)
     {
       return s1 + s2;
     }
   }
 }

The result of the output is:

Text1Tex2

2. Generic delegates

Generic delegate, if the type of parameter is uncertain, for example, the code is rewritten as:


using System;
using System.Collections.Generic;
using System.Text;

namespace TestApp
{
  /// <summary>
  ///  Delegate 
  /// </summary>
  /// <param name="s1"></param>
  /// <param name="s2"></param>
  /// <returns></returns>
  public delegate string ProcessDelegate<T,S>(T s1, S s2);

  class Program
  {
    static void Main(string[] args)
    {
      /*  Invoke method  */
      ProcessDelegate<string,int> pd = new ProcessDelegate<string,int>(new Test().Process);
      Console.WriteLine(pd("Text1", 100));
    }
  }

  public class Test
  {
    /// <summary>
    ///  Method 
    /// </summary>
    /// <param name="s1"></param>
    /// <param name="s2"></param>
    /// <returns></returns>
    public string Process(string s1,int s2)
    {
      return s1 + s2;
    }
  }
}

The result of the output is:

Text1100

The details of generics are beyond the scope of this article, so I won't say more here.

2. Events

When something happens, one object can notify another object through an event. For example, when the front desk completes the front desk interface, he informs you that you can integrate the front desk with the program you developed. This is an event. It can be seen that the event triggers another thing at one time node, and he doesn't care how to do the other thing. As far as events are concerned, the key point is when and who to do it.

In C #, the time definition keyword is event. For example:

event ProcessDelegate ProcessEvent;

The whole event definition method and execution process:


using System;
using System.Collections.Generic;
using System.Text;

namespace TestApp
{
  /// <summary>
  ///  Delegate 
  /// </summary>
  /// <param name="s1"></param>
  /// <param name="s2"></param>
  /// <returns></returns>
  public delegate void ProcessDelegate(object sender, EventArgs e);

  class Program
  {
    

    static void Main(string[] args)
    {
      /*  No. 1 1 Step execution  */
      Test t = new Test();
      /*  The method of associating events is equivalent to finding the principal  */
      t.ProcessEvent += new ProcessDelegate(t_ProcessEvent);
      /*  Enter Process Method  */
      Console.WriteLine(t.Process()); 

      Console.Read();
    }

    static void t_ProcessEvent(object sender, EventArgs e)
    {
      Test t = (Test)sender;
      t.Text1 = "Hello";
      t.Text2 = "World";
    }
  }

  public class Test
  {
    private string s1;

    public string Text1
    {
      get { return s1; }
      set { s1 = value; }
    }

    private string s2;

    public string Text2
    {
      get { return s2; }
      set { s2 = value; }
    }


    public event ProcessDelegate ProcessEvent;

    void ProcessAction(object sender, EventArgs e)
    {
      if (ProcessEvent == null)
        ProcessEvent += new ProcessDelegate(t_ProcessEvent);
      ProcessEvent(sender, e);
    }

    // If you do not specify your own associated method, it will be called to throw an error 
    void t_ProcessEvent(object sender, EventArgs e)
    {
      throw new Exception("The method or operation is not implemented.");
    }

    void OnProcess()
    {
      ProcessAction(this, EventArgs.Empty);
    }

    public string Process()
    {
      OnProcess();
      return s1 + s2;
    }
  }
}

What do you feel? Is it similar to code injection, which is equivalent to injecting any code that conforms to the delegate interface (the delegate is really like an interface) into the Process procedure. Assign him a value before he returns.

3. Callback function

I'm so tired after typing so many words!

Callback function is to pass one method to another method to execute. There are many callback functions in C #, such as asynchronous operation. Here's an example:


using System;
using System.Collections.Generic;
using System.Text;

namespace TestApp
{
  /// <summary>
  ///  Delegate 
  /// </summary>
  /// <param name="s1"></param>
  /// <param name="s2"></param>
  /// <returns></returns>
  public delegate string ProcessDelegate(string s1, string s2);

  class Program
  {
    static void Main(string[] args)
    {
      /*  Invoke method  */
      Test t = new Test();
      string r1 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process1));
      string r2 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process2));
      string r3 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process3));

      Console.WriteLine(r1);
      Console.WriteLine(r2);
      Console.WriteLine(r3);
    }
  }

  public class Test
  {
    public string Process(string s1,string s2,ProcessDelegate process)
    {
      return process(s1, s2);
    }

    public string Process1(string s1, string s2)
    {
      return s1 + s2;
    }

    public string Process2(string s1, string s2)
    {
      return s1 + Environment.NewLine + s2;
    }

    public string Process3(string s1, string s2)
    {
      return s2 + s1;
    }
  }
}

Output:

Text1Text2
Text1
Text2
Text2Text1

The Process method calls a callback function, although only the callback function is executed here. As you can see, you can pass in any one method that matches this delegate, which means that this part of the code is mutable. The design has a principle of pulling out the variable part of the code, and this usage can undoubtedly be used in that situation.


Related articles: