The example of this paper is analyzed. The limitation and extension of the net event listening mechanism. Share to everyone for your reference. The specific analysis is as follows:
. NET, the "event" as a basic programming concept, and provides a very beautiful syntax support, for example, the following C # and Java code can see the differences between the two languages design ideas.
Copy Code code as follows:
C#
Somebutton.click + = Onsomebuttonclick;
Copy Code code as follows:
Java
Somebutton.addactionlistener (
New ActionListener () {
public void actionperformed () {
...
}
});
In our software there is a lot of use of events to decouple listeners from publishers, but there are some limitations to share with one or two. First, the listener's call order cannot be guaranteed, and the second is the efficiency of listening and releasing the listener.
Call order of event listeners
. NET's event listener mechanism has no explicit guarantee to the listener's order of invocation, but sometimes we ask to ensure the order of processing between different components. For example, a component called an interaction source is responsible for assigning an event on a UI control to a set of components called an interaction in our software, in a manner similar to the interpreter pattern, in order to obtain an opportunity for event processing, in turn, in accordance with predetermined priorities. A lower-priority component can perform further processing only if a high-priority interaction does not handle the event. In this way, we can reuse them in the implementation of different business functions by organizing the interactions in different order. For example, reuse some basic view scaling, translation, menu processing and other functions.
In the above scenario, it is important to ensure that the sequence of event processing between the interactions becomes significant. Of course, if you look at the MulticastDelegate source code, you can know in the current implementation in fact, each listener still has a certain sequence of calls. But one way this is the implementation detail, which is likely to change in the future; If different listeners are in different modules, it is difficult to rely on this implementation to ensure that the sequence of calls between them is guaranteed.
Here we draw on the way in Java to handle event handling in the interface and receive a parameter that represents precedence while adding listeners, so that the order of each listener can be maintained explicitly, as shown in the following code. We define the corresponding method for each UI event in the Iinteractor interface, and let Interactsource be responsible for converting the events on the control into calls to the corresponding methods in the docking port.
Copy Code code as follows:
public class Interactsource
{
public void Addinteractor (int priority, Iinteractor interactor)
{
}
}
public interface Iinteractor
{
public void OnMouseDown (MouseEventArgs e)
{
}
... ...
}
Efficiency of listener additions and removal
MulticastDelegate is the implementation behind the event mechanism that we normally use, and it can be seen by its source code that it internally uses arrays to hold references to individual listeners. This creates a problem-the efficiency of adding and removing listeners becomes very low when the number of listeners to an event is large. To remove as an example, for an event with n listeners, an average N/2 comparison is required to determine the location of the listener, and an additional array collation is required. In order to solve this situation, we first try to define the addition of the event, remove the logic, and try to use the dictionary, hash table, etc. in a variety of ways to store, but it turns out that although the two have advantages in terms of time complexity, but the actual efficiency is not up to the requirements.
The best state is to have a data structure that can add and remove listeners in constant time, and you may also think of a two-way list.
You might think again--adding and deleting a two-way list is a constant time, but the lookup is still the complexity of O (n).
Once again, using the form of an interface as a design, we can design the event Publisher in the form of the following (schematic code):
Copy Code code as follows:
public class EventSource
{
Private LinkedList list = new LinkedList ();
Public Tocken AddListener (Ieventlistener Listener)
{
LinkedListNode n = new LinkedListNode (listener);
List. AddLast (n);
return new Tocken (node);
}
public void RemoveListener (Tocken tocken)
{
List. Remoe (Tocken.node);
}
public class Tocken
{
Internal LinkedListNode node;
}
}
In this class, a two-way list is used to store the listeners that have been added, and the added list node is returned in a token (Token) each time the AddListener method is invoked. The listener needs to save the token and use it to unlock the listener. Of course, the listener can completely ignore what the token is, like a subway ticket is always just a ticket, we don't care what it contains information. However, for the publisher can be a number of positioning information stored in it, so that the full use in the release of listening, in the above code I have saved the reference list node, so that the listener's add, locate, remove all in constant time to complete.
Of course, you can also save the publisher's reference in Tocken so that you can find bugs such as "suppress listening to an object that has never been monitored." Or, there are other information.
I hope this article will help you with the C # program.