📜 ⬆️ ⬇️

C # Events Humanly


It is impossible, just to grasp and penetrate into this deep meaning, studying Events (events) in the spaces of the basic and, at first glance, infinite C #.

When I studied Events (not within the framework of .NET!), I spent a lot of effort to finally figure out how they work and should be constructed. Therefore, I decided to publish my own methodology for understanding the structure of a user event , which is the event keyword in C #.
I will not quote the already tortured MSDN , but I will try to explain clearly and accessiblely.


What you need to learn:

An event is nothing more than a situation in which it occurs, an action or several actions will occur. Speaking in terms of software modeling, an Event is a named delegate, when invoked, all the methods of a given signature that are signed at the time of the event call will be launched. This interpretation, although it reveals the whole essence of the structure of the event, but not only confuses the beginners of “Sharp progers”, but does not make it possible to rationally present the whole meaning in the programmer's head.
')
So, an Event is a situation, in the event of which, some actions will occur. The event itself has a specific structure.

Suppose there is such a task: three classes are defined. The first class will count to 100 using a loop. The other two classes will wait for the counter in the first class to calculate, for example, up to 71, and after that everyone will output the phrase “It's time to act, after all, 71!” To the console. Simply put, when detecting the value 71, they will be called by the method, respectively, for each class. Putting everything on the shelves.

1. Simulation of the situation.

Prepare these three simplest classes, leaving the entry point to the main program untouched.
ClassCounter class and its Count () method in which the count will be produced. (In the code I omit the namespace namespace , for it is as clear as day).

class ClassCounter //  -    . { public void Count() { //    } } 

Two other classes (named after Handler_I and Handler_II ), which should respond to an event occurring using public void Message () methods. Each according to the method, as agreed.

  class Handler_I // ,    (  71)    . { public void Message() { //  using System //     Console.WriteLine(" ,   71!"); } } 

  class Handler_II { public void Message() { Console.WriteLine(",  71!"); } } 

Let me remind you that when the counter counts up to 100 and reaches 71, the Message () methods for the Handler_I and Handler_II classes should work.
Now let's go back to the ClassCounter class and create a counter using the for loop with the counter variable int i .

  class ClassCounter //  -    . { public void Count() { for (int i = 0; i < 100; i++) { } } } 

The first stage is completed. We have a class counter and two classes that will display messages. Conditions of the problem: as soon as i = 71 , the Message () methods for the two classes Handler_I and Handler_II should work.

2. Registration of the event.

We abstract from programming. The event we want to create will represent the phrase "... the counter counts. And as soon as it is equal to 71, actions must be executed." So, we need the condition "as soon as it is equal to 71". We represent it using the conditional operator if .

  class ClassCounter //  -    . { public void Count() { for (int i = 0; i < 100; i++) { if (i == 71) { } } } } 

Construct an event event . We determine by the methods that should work when i = 71 their signature (or prototype).
The signature of the method is the so-called specification (or simple words "pattern") of a. method or methods. It is a combination of the type name that the method returns, plus the name of the types of the input parameters (in order! Order is very important.)
For example, the int method NewMethod (int x, char y) will have the signature int (int, char) , and the void method NewMethod () will void (void) .
As interpreted by MSDN , events (event) are based on delegates (delegate), and the delegate, in very simple language, is “a variable storing a reference to a method”. As you already understood, because our event will refer to two methods void Message (), we must determine the signature of these methods, and make a delegate based on this signature. The signature looks like this: void (void) .

Define a delegate (let's call it MethodContainer):

  class ClassCounter //  -    . { //   ,     : //delegate < > (<  >); //   void Message().   ,   . public delegate void MethodContainer(); public void Count() { for (int i = 0; i < 100; i++) { if (i == 71) { } } } } 

Next, we create an event using the event keyword and associate it with this delegate ( MethodContainer ), and, therefore, with methods that have a void (void) signature. The event must be public, because it must be used by different classes that need to be reacted in some way (classes Handler_I and Handler_II).
The event has the syntax: public event <Name of the Delegate> <Name of the Event>;
The delegate name is the name of the delegate to which our methods “refer”.

  class ClassCounter //  -    . { public delegate void MethodContainer(); // OnCount c   MethodContainer. public event MethodContainer onCount; public void Count() { for (int i = 0; i < 100; i++) { if (i == 71) { } } } } 

Now let's run our onCount event, in the condition when i = 71:

 if (i == 71) { onCount(); } 

Everything. Event created . The methods that this event triggers are determined by signatures and a delegate is created based on them. The event, in turn, is created based on the delegate. It's time to show the onCount event, which methods should work (after all, we indicated only their signature).

3. Subscription.

Let's return to the entry point of the program main and create an instance of the class ClassCounter . And also create instances of classes that should start. (They must be public ).

  class Program { static void Main(string[] args) { ClassCounter Counter = new ClassCounter(); Handler_I Handler1 = new Handler_I(); Handler_II Handler2 = new Handler_II(); } } 

Now we specify the onCount event, the methods that should be launched.
This happens as follows: <ClassOrObject>. <EventName> + = <ClassHeyMethod Must Started>. <MethodAppropriateSignature> .
No brackets after the method! We do not call him, but simply indicate his name.

  class Program { static void Main(string[] args) { ClassCounter Counter = new ClassCounter(); Handler_I Handler1 = new Handler_I(); Handler_II Handler2 = new Handler_II(); //   Counter.onCount += Handler1.Message; Counter.onCount += Handler2.Message; } } 


Check.

Now it remains to run the ClassCounter class counter and wait for i to be equal to 71. As soon as i = 71, the onCount event is triggered by the MethodContainer delegate, which (in turn) starts the Message () methods that have been subscribed to the event.

  class Program { static void Main(string[] args) { ClassCounter Counter = new ClassCounter(); Handler_I Handler1 = new Handler_I(); Handler_II Handler2 = new Handler_II(); Counter.onCount += Handler1.Message; Counter.onCount += Handler2.Message; //  Counter.Count(); } } 

Result:
It's time to act, because already 71!
Similarly, already 71!

Conclusion

Try to understand the meaning and order of the event.

The class in which you create an event (generate) is called a publisher class, and the classes whose methods subscribe to this event with the help of "+ =" are subscriber classes.

Remember! If you have not subscribed to the event and its delegate is empty, an error will occur.
To avoid this, it is necessary to subscribe, or not to trigger an event at all, as shown in the example (since the event is a delegate, its absence is a “null reference” null ).

  if (i == 71) { if (onCount != null) { onCount(); } } 

You can always unsubscribe using the " - = " operator: <ClassOrObject>. <EventName> - = <ClassCeyMethod Must Started>. <MethodAppropriateSignature>.

The advantage of Events is obvious: the publisher class that generates the event does not need to know how many subscriber classes subscribe or unsubscribe. He created an event for certain methods, limiting them to a delegate for a particular signature.
Events are widely used to create your own control components (buttons, panels, etc.).

The smallest ones may have a question: what to do if the methods that should work have an incoming parameter (or even more than one!)?
Answer: It's all about the delegate on whom the event is based. Or rather, the signature of methods suitable for the delegate. When you construct a delegate that “accepts” a method with a parameter, then (!) The event will trigger this parameter when it starts. Naturally, the parameter can be anything.

A few words about .NET-events. Microsoft has simplified the task of constructing delegates: .NET offers a ready-made EventHandler delegate, and so on. The "batch" of EventArgs input parameters. Want an event? You take the finished EventHandler, define it in the parameters, “push” them into the class , and inherit the class from the EventArgs. And then - as scheduled)

Many developers claim (and I agree with them) that the main problem of “misunderstanding” of events is their specific field of application, and as a result, there are few examples available. Well, do not forget about the practice.

PS If you have never used delegates, better try to practice on delegates, and then try to understand this article.
I hope I brought a little insight into this difficult topic. Successes!

Source: https://habr.com/ru/post/213809/


All Articles