C # human events


It is impossible, just to take and delve into this deep meaning, studying Events in the open spaces of basic and, at first glance, infinite C #.

When I studied Events (not within the framework of .NET!), I spent a lot of energy to finally figure out how they are arranged and should be constructed. Therefore, I decided to publish my methodology for understanding the structure of a user event , which seems to be the event keyword in C #.
I will not cite the already tortured MSDN , but I will try to explain it clearly and readily.


What do you need to learn:
  • 1. You should not be afraid of learning. Please read slowly and thoughtfully.
  • 2. You must understand the classes and methods.
  • 3. You must know to understand that there are delegates. Although, you can try to understand them while reading the article.

An event is nothing more than a situation when it occurs, an action or several actions will occur. In the language of software modeling, an Event is a named delegate, upon invocation of which, all methods of a given signature that were signed at the time of the invocation of the event will be launched. This interpretation, although it reveals the essence of the structure of the event, is not only confusing for beginners “sharper progers,” but it does not make it possible to rationally present the whole point in a programmer’s head.

So, an Event , this is a situation when it occurs, some actions will occur. The event itself has a certain structure.

Suppose the task is: three classes are defined. The first class will count to 100 using a loop. The other two classes will wait for the counter to count, for example, to 71 in the first class, and after that each will display the phrase “It's time to act, it's already 71!” To the console. Simply put, when a value of 71 is detected, it will be called by the method, respectively, for each class. Let's put everything on shelves.

1. Modeling the situation.

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

    class ClassCounter  //Это класс - в котором производится счет.
    {
        public void Count()
        {
            //Здесь будет производиться счет
        }
    }

Two other classes (named Handler_I and Handler_II ) that should respond to the event by 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, when the counter counts to 100 and reaches 71, the Message () methods for the Handler_I and Handler_II classes should work.
Now 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 counter class and two classes that will display messages. Task conditions: as soon as i = 71 , the Message () methods for the two classes Handler_I and Handler_II should work .

2. Event design.

We abstract from programming. The event that we want to create will represent the phrase "... the counter counts. And as soon as it is 71, actions should be performed." 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)
                {
                }
            }
        }
    }

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

Define the 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 keyword event and associate it with this delegate ( MethodContainer ), and, therefore, with methods that have the signature void (void) . The event must be public, because it should be used by different classes that need to somehow react (classes Handler_I and Handler_II).
The event has the syntax: public event <DeligentName> <EventName>;
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, fire our onCount event, provided that i = 71:

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

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

3. Subscription.

Go back to the main program entry point and create an instance of the ClassCounter class . And also create an instance of the classes that should be launched. (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 indicate the onCount event , the methods that should be launched.
This happens as follows: <ClassOrObject>. <EventName> + = <ClassChayMethod MUST Start:. <Signature Suitable Method> .
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;
        }
    }


Verification

Now it remains to start the counter of the ClassCounter class and wait until i becomes equal to 71. As soon as i = 71, the onCount event will be fired by the delegate MethodContainer , which (in turn) will launch the Message () methods that were 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!
Exactly, already 71!

Conclusion

Try to understand the meaning and order of creating the event.
  • 1. Define the condition of the event and the methods that should work.
  • 2. Define the signature of these methods and create a delegate based on this signature.
  • 3. Create a public event based on this delegate and call when the condition works.
  • 4. Be sure to (anywhere) subscribe to this event by the methods that should work and whose signatures are suitable for the delegate.

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

Remember! If you did not subscribe to the event and its delegate is empty, an error will occur.
To avoid this, you must subscribe, or not call the 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> - = <ClassCheyMethodMustStart>> <Method SuitableSignature>.

The advantage of Events is obvious: the publisher class that generates the event does not need to know how many subscription classes are subscribing or unsubscribing. He created an event for certain methods, restricting them to a delegate for a specific signature.
Events are widely used to compose custom control components (buttons, panels, etc.).

For the smallest, the question may arise: what to do if the methods that should work have an input parameter (or even more than one!)?
Answer: It is all about the delegate on which the event is based. More precisely, the signature of methods appropriate for the delegate. When you construct a delegate that "accepts" a method with a parameter, then (!) When the event starts, it will request this parameter. Naturally, a parameter can be anything.

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

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

PS If you have never used delegates, better try practicing on delegates, and then try to understand this article.
I hope that I have contributed a little understanding to this difficult topic. Good luck!

Also popular now: