Re: Maintain list of attached event handlers (.Net 1.1)
- From: "Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx>
- Date: Tue, 10 Jul 2007 21:27:37 -0700
On Tue, 10 Jul 2007 20:43:20 -0700, Armin Zingler <az.nospam@xxxxxxxxxx> wrote:
You twice say that it is not a problem (to immediatelly unsubscribe). So, we can say that it is up to me. [...]
That's fine. My point is that you should stop bringing it up. Your requirement to unsubscribe when the event fires is completely independent of how you unsubscribe other events later. The implementation of one has no effect on the implementation of the other.
So, please. Stop bringing it up. It only muddies the waters.
[...]
Why "references to references"? (I'm using VB.Net BTW) A reference to a
MulticastDelegate object is possible. The event is a MulticastDelegate
object.
A basic rule of event management is that when you subscribe the first handler, the reference to the event has to be instantiated. Likewise, when you unsubscribe the last hander, the reference has to be set to null. Only if you have access to that reference can this be done. Having a reference to the object itself is useless.
My inference was that this inability to modify the event reference itself was the crux of your concern. But perhaps I was wrong. It doesn't matter. You are still making the task much harder than it needs to be. (An alternative explanation is that you are not describing your problem correctly...I don't know. Only through discussing it will you be able to figure that out and clarify what you mean).
As near as I can tell, you are doing what I described above, in that
you retain a reference to the object containing the event rather
than to the event itself. Frankly, I don't know why you think that
this is worse than having a reference to the event.
Because it's more work. If I have to reference the object, I will have to
handle different object types and different events individually. I just want
a simple loop:
for each item in mylist
removehandler ...
-or-
[delegate].Remove ...
next
So write the simple loop. Keep one list for each event that you might subscribe to. For each list, you know what the event is, and you know what the handler delegate is. You can easily write those explicitly. Assuming your object is type MyObj, the event for the list named lmyobj1 is MyObj.MyEvent, and you are using the method MyHandler for the event, you'd just enumerate the list like this:
foreach (MyObj myobj in lmyobj1)
{
myobj.MyEvent -= MyHandler;
}
No need for all the extra classes you're writing.
There are, however, some things that don't make sense to me in your
code.
Sorry, but everything makes sense and works well.
That don't make sense TO ME. Whether it makes sense to you is irrelevant. If you want help, you need to make sure that things make sense to the people trying to help.
As for "works well"...if it works well, why are we here? Why not just use that code?
I don't remove anything twice. After removing the handler, I remove the item
from the list. If it's not in the list anymore, it won't be removed again
when the Form is destroyed.
You do remove the event handler twice. This is the code you posted:
RemoveHandler Status.Started, AddressOf OnCodeBlockStarted
For Each item As HookedStartedEvent In f_HookedStartedEvents
If item.obj Is Status Then
item.Remove()
f_HookedStartedEvents.Remove(item)
Exit For
End If
Next
You'll notice that in the HookedStartedEvents, the Remove() method looks like this:
Public Sub Remove()
RemoveHandler obj.Started, handler
End Sub
You execute this method when item.obj == Status, which is the obejct from which you just removed the handler. In other words, first you call RemoveHandler to remove the handler from Status.Started, then you call item.Remove() which does the exact same thing.
You are right, the loop to find the item in the list was a quicky. Could be
a hashtable or whatever. But it doesn't matter. If you want to remove
something from a list, it has to be done.
You would prefer to add a hashtable to your program, with all of the memory overhead that requires, than simply allow a delegate reference to stick around after you know it won't be used?
Ever hear the phrase "penny-wise, pound-foolish"?
> It shows that I currently have to handle each event individually.
> It was a lot to type even though there were only two events.
Not that I think that the method that it appears you are using is
all that great anyway, but I don't see how typing 13 lines for a
class specific to the event is really all that big of a deal.
Compared to
class Item
event as multitaskdelegate
eventhandler as delegate
end class
it is pretty much to type,
It seems to me that you are getting stuck here. You need to forget the possibility of maintaining some general-purpose reference to the event. It's not possible, and not needed. As long as you continue to view this problem only through that narrow view, you will continue to miss the forest for the trees.
You need to think "outside the box" that you have created for yourself, and see that the basic mechanism by which you are intent on solving the issue is not required and is leading you to want to do things that .NET simply doesn't allow.
and in real-world there are some more events, as
a consequence some more "Class HookedXYZEvent", and some more arraylist and
some more loops to process the arraylists. If I could keep it all in one
list (of course, without different types of list items), it would be simple
in one go.
Again:
You say you already have an enumeration of your tree that subscribes to the events. While you didn't actually post any code that showed such an enumeration, I will take as granted that somewhere you actually do.
The solution here is to simply repeat the same enumeration at the point in time that you want to unsubscribe the events still subscribed (when the form unloads or closes or whatever). Forget about whether you've already also unsubscribed events that you know won't be raised. That doesn't matter. You can do that if you like, it doesn't change the solution for dealing with the form closing case.
Just enumerate all your objects, and unsubscribe the same event handlers that you subscribed at the start. It's simple, it works, and is MORE performant than trying to maintain a list or lists or other data structures as various events are raised and unsubscribed from.
[...]
Comments:
- You see that the MCD properties make the internal MCDs public.
Sort of. You don't have access to the actual event. What you get is a copy of the event. It's just like assigning the event to a local variable in a function. You don't get a reference to the original multicast delegate; you get a complete copy. If the multicast delegate changes later, the copied reference does not change.
- This enables me storing a reference on them externally.
No, it doesn't. It enables you to store a copy of the multicast delegate externally.
- This is usually not done, but only in this example. At least it is not
possible with classes authored by somebody else.
- The main point: In the loop that removes the handles, I don't have to care
about the object types and the events. All in one go!
You didn't show the enumeration to initialize the handlers. However, the unsubscribing is not different from the subscribing. So if it's okay to write the code to subscribe, it should be fine to write the same code to unsubscribe.
In addition: I don't
have to write one Item class for each event I want to handle.
That's right, you don't. You wouldn't if you followed the advice that both John and I have offered as well.
Though, why I wrote it "almost" works: What I did not know until know is
that the invocation list of a MultiCastDelegate object (MCD) seems to be
readonly. I can only remove one item from the invocation list by creating a
new MCD. As a consequence, I would have to store the new MCD back in the
object - which is obviously not an option and not possible at all for
foreign classes.
Exactly. That's my point. What you're trying to do is not supported by the framework.
Bottom line, the example shows how to store the information that I want to
store: I want to remember that I added /this/ handler to /that/ event
without individual handling different objects and events because the
event concept is the same for all of them. I also think that the example
makes clear what was my intention, and that it is - almost - possible. :-)
Let me see if I can put the problem another way:
You have stumbled across what you believe to be a nail. Because of this, you built a hammer that you want to apply to the nail. No matter what I or John or anyone else say, you insist on using the hammer. Even though it turns out that you don't have a nail at all. You've got a screw, and it can be dealt with more effectively using a more appropriate tool than a hammer.
[...] Now it turned out that under the hood called
"Events" there is something going on that makes it impossible to work as
intended.
As intended by whom? You? Yes, that seems to be true. It appears to be impossible to do what you seem to be dead-set on doing.
The rest of us? Not so much. We take what we know about events, and apply that knowledge in a different way, coming up with solutions that are efficient and work _with_ the existing architecture of events, rather than fighting it.
Just enumerate your tree when the form unloads, unsubscribing all the events you subscribed when the form loaded. You'll be much happier, your code will work fine, and you won't have to add a whole bunch of new classes, one for each event.
Try it, you'll like it!
Pete
.
- Follow-Ups:
- Re: Maintain list of attached event handlers (.Net 1.1)
- From: Armin Zingler
- Re: Maintain list of attached event handlers (.Net 1.1)
- References:
- Maintain list of attached event handlers (.Net 1.1)
- From: Armin Zingler
- Re: Maintain list of attached event handlers (.Net 1.1)
- From: John Saunders [MVP]
- Re: Maintain list of attached event handlers (.Net 1.1)
- From: Armin Zingler
- Re: Maintain list of attached event handlers (.Net 1.1)
- From: Peter Duniho
- Re: Maintain list of attached event handlers (.Net 1.1)
- From: Armin Zingler
- Maintain list of attached event handlers (.Net 1.1)
- Prev by Date: Re: ClickOnce Problem with .NET Framework Installation
- Next by Date: Re: ClickOnce Problem with .NET Framework Installation
- Previous by thread: Re: Maintain list of attached event handlers (.Net 1.1)
- Next by thread: Re: Maintain list of attached event handlers (.Net 1.1)
- Index(es):
Relevant Pages
|