1 Entrustment
Defining "delegate" in .NET requires the delegate keyword, which is a reference type variable that contains references to a method, similar to a pointer to a function in C or C++. "Trust" has two main functions:
(1) Pass the method as a parameter
(2) A polymorphism of the method (similar to a method template, which can match many methods)
Below, a delegate code example showing the above two functions are given:
//Define a delegate public delegate int MyDelegate(int x, int y); //A method to match the delegate public static int Add(int a, int b) { return a + b; } // Another way to match the delegate public static int Reduce(int a, int b) { return a - b; } //Example: Pass the delegate/method as parameter public static int Test(MyDelegate MD) { return MD(10, 20); } static void Main(string[] args) { int a, b, x, y; MyDelegate md; //Point the delegate to the Add method and perform related operations md = Add; a = md(1, 2); b = Test(md); //Point the delegate to the Reduce method and perform related operations md = Reduce; x = md(7, 2); y = Test(md); ($"1+2={a},10+20={b},7-2={x},10-20={y}"); (); }
Execute the above program and the output results are as follows:
1+2=3,10+20=30,7-2=5,10-20=-10
Delegation can also use +=/-= to implement the "Publish/Subscribe" mode. The sample code is as follows:
//Define a delegate public delegate void MyDelegate1(int x); public static void Method1(int a) { ($"a={a}"); } public static void Method2(int b) { ($"b={b}"); } static void Main(string[] args) { MyDelegate1 md = null; md += Method1; md += Method2; md(35); (); }
The above program output is as follows:
a=35
b=35
But delegate has a disadvantage, it can use "=" to cancel all subscriptions that have been subscribed, and only retain the subscription after =.
In order to solve this disadvantage, the event event came into being.
2 Events - the introduction of concepts
Event event is a special delegate, it can only +=, -=, and cannot be used directly.
Event can be directly = in the definition class (publisher), but in other classes (subscribers) can only += -=.That is to say, after the publisher publishes an event, the subscriber can only subscribe and cancel it to him.
Here is the code that defines an event:
//Define a delegate public delegate void MyDelegate1(int x); //Define an event public event MyDelegate1 emd;
After a long accumulation of experience, people found that the definition of most events is defined using public delegate void XXX(object sender, EventArgs e); such a commissioned prototype is a repetitive work, so EventHandler came into being. It appears to avoid this repetitive work, and it is recommended to use this type as a prototype of the event as much as possible.
//@sender: The object that raised the event//@e: Parameters passedpublic delegate void EventHandler(object sender, EventArgs e); //usepublic event EventHandler emd;
Here is a specific example of using events:
public class Demo { public event EventHandler emd; public void RaiseEvent() { emd(this, ); } } static void Main(string[] args) { var instance = new Demo(); += (sender, arg) => { ("Execution Event 1!"); }; += (sender, arg) => { ("Execution Event 2!"); }; (); (); }
Here we first define a Demo class, which has an event inside it is emd. We open an interface RaiseEvent to it. If anyone dares to call it, then it triggers the alarm event emd.
Here we simulate two subscribers to handle alarm events emd respectively.
The program execution results are as follows:
Execution Event 1!
Execute Event 2!
At the same time, we can also see:Events are executed in order of subscriptions of +=.
3 Events-About Exception
Now, we include exceptions in our first subscriber, as follows:
+= (sender, arg) => { ("Execution Event 1!"); throw new Exception("Execution event 1, error"); };
After execution, it was found that after the first subscriber event triggered an exception, the second subscriber event was not executed.
It can be seen that if you want all subscribers to perform processing, each subscriber must handle the exception by himself in the subscription program and cannot be thrown out!
4 Events-About Asynchronous
What happens if one of the subscribers of the event is "asynchronous" processing?
Next, we change the first subscriber to asynchronous processing, the code is as follows:
+= async (sender, arg) => { ("Execution Event 1!"); await (1000); ("Execution Event 1! Completed"); };
After execution, the output is as follows:
Execution Event 1!
Execute Event 2!
Execution event 1! Completed
It can be seen that asynchronous event processing does not block the process, which plays a good role in an asynchronous method.
5. Commission-Func and Action
This article first discusses commissioning, and then goes directly to the topics related to the incident. In fact, there is another key topic about commissioning, that is, Func and Action.
Long after the delegation delegate appeared, Microsoft's .NET designers finally realized that in fact, all delegation definitions can be summarized and simplified to express only using the two syntax sugars of Func and Action. Among them, Func represents a delegate with a return value, and Action represents a delegate with a return value. With them, we no longer need to use the keyword delegate to define the delegation in the future.
At the same time, if the lambda expression is used instead of the specific method pointed to by the delegate,Then the two steps of "definition + assignment" of the entire delegation will be greatly simplified.(The lambda expression is originally a simplified form of method definition).
Below, the program code on addition and subtraction in the initial delegation chapter is simplified and modified with Func and lambda expressions. The modified code is as follows:
//Example: Pass the delegate/method as parameter public static int Test(Func<int, int, int> MD) { return MD(10, 20); } static void Main(string[] args) { int a, b, x, y; Func<int, int, int> md; //Point the delegate to addition and perform related operations md = (t, v) => t + v; a = md(1, 2); b = Test(md); //Point the delegation to subtraction and perform related operations md = (t, v) => t - v; x = md(7, 2); y = Test(md); ($"1+2={a},10+20={b},7-2={x},10-20={y}"); (); }
Is the code greatly simplified? What has been simplified? You can compare it before and after...
The above is a detailed explanation of the use and differences between delegate/event/EventHandler/Action/Func in C#. For more information about delegate event EventHandler Action Func, please follow my other related articles!