Hi,

here's the short version:
How can I remember which event handlers did I attach to which events?

Background:
- I have an object tree. There is one root object, containing sub objects,
containing sub objects, and so on. All the objects in the tree can raise
events.

- In a Form's Load event, I recursively process the object tree and attach
event handlers to all the events of the objects in the tree.

- Whenever an event fires, I detach the event handler. (because it won't
fire twice)

- When the Form closes, maybe not all events have been fired. Therefore,
there are still event handlers attached to these events.

My goal is:
I must detach the remaining event handlers when closing the Form.

Question:
How do I know which event handlers are still attached? I thought I simply
could maintain a list of attached event handlers. Whenever an event fires,
I detach the event handler and remove the corresponding entry from the
list. So, if the Form closes, I only have to process the list in order to
detach the remaining handlers.

But, /what/ do I have to store in the list? I didn't find a way without
using Reflection.

Thanks for reading!


Armin

Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Tue Jul 10 16:11:49 CDT 2007

On Tue, 10 Jul 2007 13:40:17 -0700, Armin Zingler <az.nospam@freenet.de>
wrote:

> [...]
> - In a Form's Load event, I recursively process the object tree and
> attach
> event handlers to all the events of the objects in the tree.
>
> - Whenever an event fires, I detach the event handler. (because it won't
> fire twice)
>
> - When the Form closes, maybe not all events have been fired. Therefore,
> there are still event handlers attached to these events.
>
> My goal is:
> I must detach the remaining event handlers when closing the Form.

I don't see any need to detach the event handler regardless. It is not
really hurting anything for it to remain attached even after the event
fires, other than a very minimal amount of memory occupied. And if you
are releasing the object itself, any attached event handlers will also be
released at that time, without you doing anything extra.

Why is it that you think you need to detach the event handlers?

Pete

Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Tue Jul 10 16:48:20 CDT 2007

"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> schrieb
> On Tue, 10 Jul 2007 13:40:17 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
>
> > [...]
> > - In a Form's Load event, I recursively process the object tree
> > and attach
> > event handlers to all the events of the objects in the tree.
> >
> > - Whenever an event fires, I detach the event handler. (because it
> > won't fire twice)
> >
> > - When the Form closes, maybe not all events have been fired.
> > Therefore, there are still event handlers attached to these
> > events.
> >
> > My goal is:
> > I must detach the remaining event handlers when closing the Form.
>
> I don't see any need to detach the event handler regardless. It is
> not really hurting anything for it to remain attached even after the
> event fires, other than a very minimal amount of memory occupied. And if
> you are releasing the object itself, any attached event
> handlers will also be released at that time, without you doing
> anything extra.
>
> Why is it that you think you need to detach the event handlers?

The Form is an observer of some objects working in the background in another
thread. After the Form has closed, it doesn't have to observe the events
anymore. In the event handlers, I call Me.BeginInvoke to marshal the work to
the UI thread, but as there is no Form, there is no need to do this anymore.
Of course, I could always query "IsHandleCreated" in each event handler, but
I think it's straighter to detach the event handlers when closing the Form.


Armin


Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Tue Jul 10 17:36:52 CDT 2007

On Tue, 10 Jul 2007 14:48:20 -0700, Armin Zingler <az.nospam@freenet.de>
wrote:

> The Form is an observer of some objects working in the background in
> another thread. After the Form has closed, it doesn't have to observe
> the events anymore. In the event handlers, I call Me.BeginInvoke to
> marshal the work to the UI thread, but as there is no Form, there is no
> need to do this anymore. Of course, I could always query
> "IsHandleCreated" in each event handler, but I think it's straighter to
> detach the event handlers when closing the Form.

Ah, I misunderstood. Sorry. Your original wording made it sound as
though it was the objects owned by the form itself that exposed the
event. Just to clarify: the form itself does not actually contain the
tree. The tree is only in some data structure, and form subscribes to an
event (or events) on each and every object within the tree. And yes, I
agree that if the form is going away, it should unsubscribe itself from
any events to which it's subscribed.

It is not a problem to unsubscribe from an event that you are not
subscribed to. So one option is to simply go through an unsubscribe from
every event when the form unloads, just as you go through and subscribe to
every event when the form loads.

I do not believe there is any point in unsubscribing when the event fires,
even if the event will never be raised again. So, if you agree with that
then you can simply do as I suggest above (unsubscribe to every event when
the form unloads) _without_ bothering to unsubscribe any other time.

Pete

Re: Maintain list of attached event handlers (.Net 1.1) by John

John
Tue Jul 10 18:08:49 CDT 2007

"Armin Zingler" <az.nospam@freenet.de> wrote in message
news:eEhlPQzwHHA.3364@TK2MSFTNGP02.phx.gbl...
> Hi,
>
> here's the short version:
> How can I remember which event handlers did I attach to which events?
>
> Background:
> - I have an object tree. There is one root object, containing sub objects,
> containing sub objects, and so on. All the objects in the tree can raise
> events.
>
> - In a Form's Load event, I recursively process the object tree and attach
> event handlers to all the events of the objects in the tree.
>
> - Whenever an event fires, I detach the event handler. (because it won't
> fire twice)

Why detach the handler right away? Why not wait until the form closes, then
detach them all? Follow the same (visitor) pattern you followed to attach
the handlers to detach them.
--
John Saunders [MVP]


Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Tue Jul 10 18:15:14 CDT 2007

"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> schrieb
> On Tue, 10 Jul 2007 14:48:20 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
>
> > The Form is an observer of some objects working in the background
> > in another thread. After the Form has closed, it doesn't have to
> > observe the events anymore. In the event handlers, I call
> > Me.BeginInvoke to marshal the work to the UI thread, but as there
> > is no Form, there is no need to do this anymore. Of course, I
> > could always query
> > "IsHandleCreated" in each event handler, but I think it's
> > straighter to detach the event handlers when closing the Form.
>
> Ah, I misunderstood. Sorry. Your original wording made it sound as
> though it was the objects owned by the form itself that exposed the
> event. Just to clarify: the form itself does not actually contain
> the tree. The tree is only in some data structure, and form
> subscribes to an event (or events) on each and every object within
> the tree.

Correct. In other words, the tree can live without the Form.

> And yes, I agree that if the form is going away, it
> should unsubscribe itself from any events to which it's subscribed.
>
> It is not a problem to unsubscribe from an event that you are not
> subscribed to. So one option is to simply go through an unsubscribe
> from every event when the form unloads, just as you go through and
> subscribe to every event when the form loads.
>
> I do not believe there is any point in unsubscribing when the event
> fires, even if the event will never be raised again. So, if you
> agree with that then you can simply do as I suggest above
> (unsubscribe to every event when the form unloads) _without_
> bothering to unsubscribe any other time.
>
> Pete

You're right, I could do this. Though, isn't it interesting that it is not
possible to store the information I need to remember? I only want to
remember "I attached this handler to that event". I am able to remember
"this handler" because it's just a Delegate, but I am not able to rember
"that event" (without using reflection).

I can not belive that it is not possible.



Armin



Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Tue Jul 10 18:50:30 CDT 2007

On Tue, 10 Jul 2007 16:15:14 -0700, Armin Zingler <az.nospam@freenet.de>
wrote:

> [...]
> You're right, I could do this. Though, isn't it interesting that it is
> not possible to store the information I need to remember? I only want to
> remember "I attached this handler to that event". I am able to remember
> "this handler" because it's just a Delegate, but I am not able to rember
> "that event" (without using reflection). I can not belive that it is not
> possible.

It is possible. You don't even need reflection. There's just no point in
it.

Pete

Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Tue Jul 10 18:57:14 CDT 2007

"John Saunders [MVP]" <john.saunders at trizetto.com> schrieb
> "Armin Zingler" <az.nospam@freenet.de> wrote in message
> news:eEhlPQzwHHA.3364@TK2MSFTNGP02.phx.gbl...
> > Hi,
> >
> > here's the short version:
> > How can I remember which event handlers did I attach to which
> > events?
> >
> > Background:
> > - I have an object tree. There is one root object, containing sub
> > objects, containing sub objects, and so on. All the objects in the
> > tree can raise events.
> >
> > - In a Form's Load event, I recursively process the object tree
> > and attach event handlers to all the events of the objects in the
> > tree.
> >
> > - Whenever an event fires, I detach the event handler. (because it
> > won't fire twice)
>
> Why detach the handler right away? Why not wait until the form
> closes, then detach them all? Follow the same (visitor) pattern you
> followed to attach the handlers to detach them.

Why /not/ detach them right away? :-) I know, because then I would not have
the problem, but in general it is not a fault to detach them immediatelly.
Though, the question remains how I can store the information that "I
attached this handler to that event".

Background:
The tree mentioned describes an execution plan in another thread. Each node
in the tree represents a piece of work. A node contains status information
and fires "Started" and "Done" events. Whenever I receive the "Started" or
"Finished" event, I unsubcribed from it because it will never fire again.
Right, I am not forced to unsubscribe immediatelly, but IMO it's more
correct than wrong. In the end, when closing the Form, I want to unsubsribe
to all remaining handlers that are still attached.

Though, it is still interesting for me that I can not store the information
in a list. Actually each item would be a pair of two objects: One pointing
to the event (type: Multicastdelegate), the other one pointing to the event
handler (Delegate).

Below[1] I inserted the real-world code that I had to write due to a lack of
solution that I am looking for. You don't have to read it because it's
lengthier. It shows that I currently have to handle each event individually.
It was a lot to type even though there were only two events. In other
situations there might be more, that's why I was looking for a general
solution.

Finally, all events are based on the same concept, so polymorphism should be
appliable here.



Armin

[1]
Private Class HookedStartedEvent
Public handler As CodeBlockInstanceStatus.StartedEventHandler
Public obj As CodeBlockInstanceStatus

Public Sub New( _
ByVal handler As CodeBlockInstanceStatus.StartedEventHandler, _
ByVal obj As CodeBlockInstanceStatus)

Me.handler = handler
Me.obj = obj
End Sub

Public Sub Remove()
RemoveHandler obj.Started, handler
End Sub
End Class

Private Class HookedFinishedEvent
Public handler As CodeBlockInstanceStatus.FinishedEventHandler
Public obj As CodeBlockInstanceStatus

Public Sub New( _
ByVal handler As CodeBlockInstanceStatus.FinishedEventHandler, _
ByVal obj As CodeBlockInstanceStatus)

Me.handler = handler
Me.obj = obj
End Sub
Public Sub Remove()
RemoveHandler obj.Finished, handler
End Sub
End Class


Private f_HookedStartedEvents As New ArrayList
Private f_HookedFinishedEvents As New ArrayList

Private Sub OnCodeBlockStarted(ByVal sender As Object)

If Me.InvokeRequired Then
BeginInvoke( _
New CodeBlockInstanceStatus.StartedEventHandler(AddressOf
OnCodeBlockStarted), _
New Object() {sender} _
)
Else
Dim Status As CodeBlockInstanceStatus

Status = DirectCast(sender, CodeBlockInstanceStatus)

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

End If

End Sub

Private Sub ThreadWatcher_HandleDestroyed( _
ByVal sender As Object, ByVal e As System.EventArgs) _
Handles MyBase.HandleDestroyed

For Each item As HookedFinishedEvent In f_HookedFinishedEvents
item.Remove
Next

For Each item As HookedStartedEvent In f_HookedStartedEvents
item.Remove
Next

f_HookedFinishedEvents = Nothing
f_HookedStartedEvents = Nothing
End Sub



Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Tue Jul 10 19:27:33 CDT 2007

"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> schrieb
> On Tue, 10 Jul 2007 16:15:14 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
>
> > [...]
> > You're right, I could do this. Though, isn't it interesting that
> > it is not possible to store the information I need to remember? I
> > only want to remember "I attached this handler to that event". I
> > am able to remember "this handler" because it's just a Delegate,
> > but I am not able to rember "that event" (without using
> > reflection). I can not belive that it is not possible.
>
> It is possible. You don't even need reflection. There's just no
> point in it.

As I am not able to store a reference to an event, I don't see how it could
be possible. There is a point in it because that's the situation. Maybe it
won't lead to an exception if I detach from an event that I have already
detached from, but I would like to detach only from those events that I am
still handling. Therefore I need a list. I'm looking forward to a way
wihtout reflection.


Armin


Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Tue Jul 10 19:53:10 CDT 2007

On Tue, 10 Jul 2007 16:57:14 -0700, Armin Zingler <az.nospam@freenet.de>=
=

wrote:

> Why /not/ detach them right away? :-) I know, because then I would not=
=

> have
> the problem,

No. That's not true. The question of being able to unsubscribe event =

handlers later has nothing to do with whether you also unsubscribe as th=
ey =

are raised. I personally think unsubscribing is a waste of time, but it=
=

doesn't affect the more general issue. So, you should stop worrying abo=
ut =

it. If you want to unsubscribe, fine. It's not causing a problem.

> but in general it is not a fault to detach them immediatelly.
> Though, the question remains how I can store the information that "I
> attached this handler to that event".

Why do you need this information? You obviously can enumerate all of th=
e =

objects for which you want to subscribe to an event or events. So, do t=
he =

same enumeration when you want to unsubscribe, and unsubscribe from ever=
y =

event of every object that you subscribed to in the first place.

For some objects, this operation will do nothing, because you've already=
=

unsubscribed. But that's not a problem.

> Background:
> The tree mentioned describes an execution plan in another thread. Each=
=

> node
> in the tree represents a piece of work. A node contains status =

> information
> and fires "Started" and "Done" events. Whenever I receive the "Started=
" =

> or
> "Finished" event, I unsubcribed from it because it will never fire aga=
in.
> Right, I am not forced to unsubscribe immediatelly, but IMO it's more
> correct than wrong.

I disagree, but you are writing the code, so obviously your opinion =

carries more weight. Regardless, as I mentioned this question has nothi=
ng =

to do with how you resolve the unsubscription at the end.

> In the end, when closing the Form, I want to unsubsribe
> to all remaining handlers that are still attached.

So do that. Traverse your tree and unsubscribe from all the events, jus=
t =

as you traversed the tree and subscribed to start with.

> Though, it is still interesting for me that I can not store the =

> information
> in a list. Actually each item would be a pair of two objects: One =

> pointing
> to the event (type: Multicastdelegate), the other one pointing to the =
=

> event
> handler (Delegate).

In C#, there are no references to references. This is a fundamental =

limitation, granted. But it doesn't prevent things from being done. It=
=

just changes how they need to be done.

In C, you might do something like this (if C allowed this syntax, that i=
s):

public event MyHandlerType myevent;

and then later do this:

MyHandlerType *pevent =3D &myevent;
*pevent +=3D MyEventHandler;

so that even later you could do this:

*pevent -=3D MyEventHandler;

That's not possible in C#. However, that doesn't mean that you can't =

instead retain a reference to the object with the event itself, and gain=
=

access to the event later that way.

So instead, you'd write something like this:

class MyEventRaisingClass
{
public event MyHandlerType myevent;
...
}

and then later do this:

MyEventRaisingClass raiser =3D ...;

raiser.myevent +=3D MyEventHandler;

and then even later do this:

raiser.myevent -=3D MyEventHandler;

The two are basically equivalent. The only difference is that in one ca=
se =

you know only the event instance, while in the other case you have the =

reference to the entire containing class instance.

> Below[1] I inserted the real-world code that I had to write due to a =

> lack of solution that I am looking for. You don't have to read it =

> because it's lengthier.

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 th=
an =

having a reference to the event. As I mentioned, it is basically =

equivalent.

There are, however, some things that don't make sense to me in your code=
.

It doesn't actually explain the issue you're asking about, because you =

don't appear to have included all of the code that does stuff. In =

particular, I don't see any of the setup, nor is clear how events are =

actually raised. But beyond that, you appear to be removing the same =

handler twice. Once in the event handling method itself:

RemoveHandler Status.Started, AddressOf OnCodeBlockStarted

And then again in the Remove() method of a class the purpose for which I=
=

have yet to determine:

Public Sub Remove()
RemoveHandler obj.Started, handler
End Sub

In addition, every time an event handler is called, you enumerate a list=
=

of all known subscribed event handlers (I think...again, you left out =

details that would clarify this). In what way is that better than simpl=
y =

enumerating all of the objects when the form is finally unloaded and =

unsubscribing from each object there? It certainly results in a lot mor=
e =

execution of code (it's essentially an O(N^2) algorithm, as opposed to t=
he =

O(N) algorithm that both John and I have proposed to you.

> It shows that I currently have to handle each event individually. It w=
as =

> 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 th=
at =

great anyway, but I don't see how typing 13 lines for a class specific t=
o =

the event is really all that big of a deal.

Pete

Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Tue Jul 10 19:58:27 CDT 2007

On Tue, 10 Jul 2007 17:27:33 -0700, Armin Zingler <az.nospam@freenet.de>
wrote:

> As I am not able to store a reference to an event, I don't see how it
> could
> be possible.

See my other post. You simply retain a reference to the object containing
the event, rather than to the event itself.

> There is a point in it because that's the situation.

Giving you the benefit of the doubt, maybe "that is the situation".
However, so far you haven't posted anything that would verify that
statement.

> Maybe it won't lead to an exception if I detach from an event that I
> have already detached from, but I would like to detach only from those
> events that I am still handling.

Why? Of what concern is it to you? Why are you insisting on doing extra
work to avoid something that is perfectly legal and efficient?

> Therefore I need a list. I'm looking forward to a way wihtout reflection.

You can do the list. You can do it without reflection (in fact, you seem
to have already done it without reflection). But even so, there's no
point to it. All you've done is make your code slower. It's
functionality is the same as if you had just unsubscribed all the events
at the end, and you do more work to accomplish the same thing.

I suppose the phrase "no point to it" is open to interpretation. But as I
see it, there's no point in doing what you seem to be asking to do.

Pete

Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Tue Jul 10 20:43:33 CDT 2007

On Tue, 10 Jul 2007 17:53:10 -0700, Peter Duniho
<NpOeStPeAdM@nnowslpianmk.com> wrote:

> [...]
>> 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.

And as a clarification for this point:

Even if you feel you must maintain a list of subscribed events, you do not
need a new class for every event type. All you need to keep is a list of
the objects for which you've subscribed; all the other information is
already known at compile time and can be referred to explicitly when you
want to unsubscribe.

I don't think the typing should be an issue anyway, but it's not really
required. So if you object to it, don't do it.

Pete

Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Tue Jul 10 22:34:48 CDT 2007

"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> schrieb
> > Maybe it won't lead to an exception if I detach from an event that
> > I have already detached from, but I would like to detach only from
> > those events that I am still handling.
>
> Why? Of what concern is it to you? Why are you insisting on doing
> extra work to avoid something that is perfectly legal and efficient?

Why do you insist on doing extra work by detaching event handlers that have
already been detached before? Why keep listening to events that will never
occur?

See other post for more.



Armin


Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Tue Jul 10 22:43:20 CDT 2007

"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> schrieb
> For some objects, this operation will do nothing, because you've
> already unsubscribed. But that's not a problem.

To make it a bit shorter, I'll try to resume:
You twice say that it is not a problem (to immediatelly unsubscribe). So, we
can say that it is up to me. But if I have the choice between either listen
to an event that will never occur, or don't listen to it anymore, the latter
obviously makes more sense. That's the reason why I unsubscribe
immediatelly.

> > Though, it is still interesting for me that I can not store the
> > information
> > in a list. Actually each item would be a pair of two objects: One
> > pointing
> > to the event (type: Multicastdelegate), the other one pointing to
> > the event
> > handler (Delegate).
>
> In C#, there are no references to references.

Why "references to references"? (I'm using VB.Net BTW) A reference to a
MulticastDelegate object is possible. The event is a MulticastDelegate
object. My only problem is that it is private in the class.
[Meanwhie I know what you might be referring to but I'm not sure yet; see my
example and the explanation at the end]

> [C]

Sorry, I can not comment the C-Code.

> [C#]
> [...]
> > Below[1] I inserted the real-world code that I had to write due to
> > a lack of solution that I am looking for. You don't have to read
> > it because it's lengthier.
>
> 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

Sort of p-Code, but that's all I am looking for.


> There are, however, some things that don't make sense to me in your
> code.

Sorry, but everything makes sense and works well.

> It doesn't actually explain the issue you're asking about, because
> you don't appear to have included all of the code that does stuff. In
> particular, I don't see any of the setup, nor is clear how events
> are actually raised.

Yes, I did not include the whole code. The code explains well how I have to
handle the different events individually because the code is not based on a
base class (like MultiCastDelegate) that is common to all events, no matter
which object and no matter which event.


> But beyond that, you appear to be removing the
> same handler twice. Once in the event handling method itself:
>
> RemoveHandler Status.Started, AddressOf OnCodeBlockStarted
>
> And then again in the Remove() method of a class the purpose for
> which I have yet to determine:
>
> Public Sub Remove()
> RemoveHandler obj.Started, handler
> End Sub
>
> In addition, every time an event handler is called, you enumerate a
> list of all known subscribed event handlers (I think...again, you
> left out details that would clarify this). In what way is that
> better than simply enumerating all of the objects when the form is
> finally unloaded and unsubscribing from each object there? It
> certainly results in a lot more execution of code (it's essentially
> an O(N^2) algorithm, as opposed to the O(N) algorithm that both John
> and I have proposed to you.

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 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.

> > 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, 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.



[Later....]
An example how it (almost) works. Comments see below.


Public Class Form1

Class C1
Public Event Progress(ByVal p As Integer)
Public ReadOnly Property MCD() As MulticastDelegate
Get
Return ProgressEvent
End Get
End Property
Public Sub Raise()
RaiseEvent Progress(0)
End Sub
End Class

Class C2
Public Event Done()
Public ReadOnly Property MCD() As MulticastDelegate
Get
Return DoneEvent
End Get
End Property
Public Sub Raise()
RaiseEvent Done()
End Sub
End Class

Private Class Item
Public [event] As MulticastDelegate
Public Handler As [Delegate]

Public Sub New(ByVal [event] As MulticastDelegate, _
ByVal Handler As [Delegate])

Me.event = [event]
Me.Handler = Handler
End Sub
End Class

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load

Dim al As New List(Of Item)
Dim o1 As New C1
Dim o2 As New C2

Dim d1 As New C1.ProgressEventHandler(AddressOf OnProgress)
Dim d2 As New C2.DoneEventHandler(AddressOf OnDone)

'add the event handlers...
AddHandler o1.Progress, d1
AddHandler o2.Done, d2

'...and remember which events I handle.
al.Add(New Item(o1.MCD, d1))
al.Add(New Item(o2.MCD, d2))

o1.Raise()
o2.Raise()

'...
'later: Remove all event handlers

For Each i As Item In al
[Delegate].Remove(i.event, i.Handler)
Next

o1.Raise()
o2.Raise()

End Sub
Private Sub OnProgress(ByVal p As Integer)
MsgBox("OnProgress")
End Sub
Private Sub OnDone()
MsgBox("OnDone")
End Sub

End Class


Comments:
- You see that the MCD properties make the internal MCDs public.
- This enables me storing a reference on them 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! In addition: I don't
have to write one Item class for each event I want to handle.

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.

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. :-)


Please don't get me wrong: I use .Net since the first public SDK preview (in
Y2K?), and I am a programmer for 20 years now, so I (usually ;-) ) know what
I do. I don't insist on anything, but I thought that events have a common
concept, common base clases, and therefore it's not absurd to
think..uhhm..what I think. Now it turned out that under the hood called
"Events" there is something going on that makes it impossible to work as
intended.

Anyways, thanks a lot for your time and trying to help!



Armin


Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Tue Jul 10 22:53:44 CDT 2007

On Tue, 10 Jul 2007 20:34:48 -0700, Armin Zingler <az.nospam@freenet.de>
wrote:

> Why do you insist on doing extra work by detaching event handlers that
> have
> already been detached before?

It's not extra work. It's _less_ work.

> Why keep listening to events that will never occur?

Having a delegate attachd to an event is not "listening". It incurs zero
performance penalty. Zero. If the memory cost is unacceptable after the
event has been raised, then it was unacceptable before it was raised. The
question of removing the delegate or not is a red herring. And leaving
the delegate subscribed does not involve any execution overhead whatsoever.

Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Tue Jul 10 23:27:37 CDT 2007

On Tue, 10 Jul 2007 20:43:20 -0700, Armin Zingler <az.nospam@freenet.de>=
=

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 independen=
t =

of how you unsubscribe other events later. The implementation of one ha=
s =

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. Havi=
ng =

a reference to the object itself is useless.

My inference was that this inability to modify the event reference itsel=
f =

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 t=
o =

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 jus=
t =

> 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 -=3D 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 u=
se =

that code?

> I don't remove anything twice. After removing the handler, I remove th=
e =

> item
> from the list. If it's not in the list anymore, it won't be removed ag=
ain
> 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 =3D=3D 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. Cou=
ld =

> 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 arraylis=
t =

> and
> some more loops to process the arraylists. If I could keep it all in o=
ne
> 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 alread=
y =

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 variab=
le =

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 delegat=
e =

externally.

> - This is usually not done, but only in this example. At least it is n=
ot
> possible with classes authored by somebody else.
> - The main point: In the loop that removes the handles, I don't have t=
o =

> care
> about the object types and the events. All in one go!

You didn't show the enumeration to initialize the handlers. However, th=
e =

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 t=
he
> 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 wan=
t =

> 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 examp=
le
> 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 b=
e =

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 a=
re =

efficient and work _with_ the existing architecture of events, rather th=
an =

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, you=
r =

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

Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Wed Jul 11 06:12:41 CDT 2007

"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> schrieb
> On Tue, 10 Jul 2007 20:34:48 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
>
> > Why do you insist on doing extra work by detaching event handlers
> > that have
> > already been detached before?
>
> It's not extra work. It's _less_ work.

I see, doing something twice is less work...? Ok. You should distinguish
between programming work and work done by the program at runtime. I'm
referring to uselessly detaching the same event handler twice at runtime. I
do accept the additional programming work to avoid this superfluous step
whereas you don't. There's nothing more I can add, not now and not in
future posts.

> > Why keep listening to events that will never occur?
>
> Having a delegate attachd to an event is not "listening".

Use the word of your choice, but I call it listening.

> It incurs
> zero performance penalty. Zero. If the memory cost is unacceptable
> after the event has been raised, then it was unacceptable before it
> was raised. The question of removing the delegate or not is a red
> herring. And leaving the delegate subscribed does not involve any
> execution overhead whatsoever.

I have never mentioned performance or memory costs. That was /you/. So, how
can it be /my/ problem? Ok, the very last time: You accept a situation that
doesn't hurt. I don't accept a situation that doesn't make sense. Having
event handlers attached to events that will never fire does not make sense
(TO ME). Sorry, I forgot you don't want to discuss this anymore. But me too,
so, please, let's stop at this point.


Armin


Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Wed Jul 11 06:23:00 CDT 2007

"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> schrieb
> [...]

Now, based on my own researches, that I found out that it is not possible to
do what I was trying, I'm closing this discussion for my part. I would have
to repeat myself again and again. I don't like that you are inappropriatly
speaking tartly. Blame me for not knowing the deepest details of how events
internally work. If that's what you are after....


BTW, my quoted conclusion in the VB.Net group:

"The problem is what's going on under the hood when adding/removing event
handlers: The AddHandler keyword doesn't expect an object as the first
argument, but it's the /name/ of an event. If it was an object, it would be
possible to store a reference. Everything done internally by executing
Addhandler is specific to the class and to the event. As it's specific,
there is no multipurpose solution that enables me storing references to
events in the way intended."


Armin


Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Wed Jul 11 16:21:40 CDT 2007

On Wed, 11 Jul 2007 04:12:41 -0700, Armin Zingler <az.nospam@freenet.de>
wrote:

>> It's not extra work. It's _less_ work.
>
> I see, doing something twice is less work...?

Yes. It's less work than doing something once, maintaining a list on an
on-going basis, and then still having to traverse the list later anyway.

> Ok. You should distinguish
> between programming work and work done by the program at runtime.

Okay, to be clear: I am talking about work done by the program at runtime.

> I'm
> referring to uselessly detaching the same event handler twice at runtime.

It's true, some times that operation will be unnecessary. However, that
doesn't mean it's more work than the alternative.

> I do accept the additional programming work to avoid this superfluous
> step
> whereas you don't.

I don't? I don't what? Accept additional programming work? That's
absurd. You have no idea what I do or do not accept, nor am I talking
about programming work.

>> > Why keep listening to events that will never occur?
>>
>> Having a delegate attachd to an event is not "listening".
>
> Use the word of your choice, but I call it listening.

And you called it "catching" too. That doesn't make it right. More
particularly, the word "listen" implies some sort of active role. You can
use the word "listen" if you like, and we will even understand you. My
point is to be sure you understand that there is no actual active
listening going on. It hurts nothing to have a delegate attached to an
event, as that involves no actual run time code execution.

>> It incurs
>> zero performance penalty. Zero. If the memory cost is unacceptable
>> after the event has been raised, then it was unacceptable before it
>> was raised. The question of removing the delegate or not is a red
>> herring. And leaving the delegate subscribed does not involve any
>> execution overhead whatsoever.
>
> I have never mentioned performance or memory costs.

Of course you did. You are complaining about having to go through every
node in your tree at the end and unsubscribe, and your complaint is based
on your incorrect assertion that that's "more work". What is that, if not
a performance-based view?

I brought up memory as a way of explaining that I do understand the memory
costs involved in leaving the delegate attached. Since that's the _only_
cost to leaving it attached, I remain mystified as to why you care about
it remaining attached, since you "never mentioned memory costs". If you
don't care about memory costs, then why do you care about the delegate
remaining attached, given that memory costs are the _only_ costs involved
in doing so?

> That was /you/. So, how
> can it be /my/ problem? Ok, the very last time: You accept a situation
> that
> doesn't hurt. I don't accept a situation that doesn't make sense.

No, actually you don't accept a situation that DOES makes sense. It's
your proposal that makes no sense. You want to go to greater effort,
_both_ with respect to your time spent programming _and_ with respect to
the run-time code execution, to avoid a situation that isn't causing a
problem in the first place.

> Having
> event handlers attached to events that will never fire does not make
> sense
> (TO ME).

Then leave them there. You still don't need to maintain a list of the
handlers you have not yet removed.

Pete

Re: Maintain list of attached event handlers (.Net 1.1) by Armin

Armin
Wed Jul 11 18:24:54 CDT 2007

"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> schrieb

[...]
> > > > Why keep listening to events that will never occur?
> > >
> > > Having a delegate attachd to an event is not "listening".
> >
> > Use the word of your choice, but I call it listening.
>
> And you called it "catching" too. That doesn't make it right. More
> particularly, the word "listen" implies some sort of active role.

That's your interpretation. As I know what events are, I know what "listen
to an event" means. As you also know what events are, you should als know
what "listen to an event" means. I have used it in the past, unless when
teaching beginners, sufficient times without misinterpretation by the
reader.

> You can use the word "listen" if you like, and we will even
> understand you. My point is to be sure you understand that there is
> no actual active listening going on.

You can be sure that I know this.

> It hurts nothing to have a
> delegate attached to an event, as that involves no actual run time
> code execution.

Let me put it this way:
A basic programming rule that I (and not only I) always obey is: Clean up
references as soon as I don't need them anymore. There is no reason to
challenge this every time. Every time, I do not have to count the bytes
potentially freed, then decide if the amount legitimates writing the
removement of the reference. Instead, I simply remove it because I don't
need it anymore. That's the basis rule.
The same with the event handler: I don't need to handle the event anymore,
consequently I remove the handler. This is also part of a whole conecept
called "clean programming".


> > > It incurs
> > > zero performance penalty. Zero. If the memory cost is
> > > unacceptable after the event has been raised, then it was
> > > unacceptable before it was raised. The question of removing
> > > the delegate or not is a red herring. And leaving the delegate
> > > subscribed does not involve any execution overhead whatsoever.
> >
> > I have never mentioned performance or memory costs.
>
> Of course you did. You are complaining about having to go through
> every node in your tree at the end and unsubscribe, and your
> complaint is based on your incorrect assertion that that's "more
> work". What is that, if not a performance-based view?

As, in this case, I don't care whether it takes 1/100 or 1/1,000 of a
second, how can it be a performance issue? Again, /you/ mentioned
"performance" first. The result of your misinterpretation of why I don't
want to do superfluous things. It's not for performance reasons. It's just
illogical to do something that does not have to be done. (yes, I know "it
doesn't hurt" - but doing something that doesn't hurt but that is not
necessary is still illogical)

> I brought up memory as a way of explaining that I do understand the
> memory costs involved in leaving the delegate attached. Since
> that's the _only_ cost to leaving it attached, I remain mystified as
> to why you care about it remaining attached, since you "never
> mentioned memory costs". If you don't care about memory costs, then
> why do you care about the delegate remaining attached, given that
> memory costs are the _only_ costs involved in doing so?

see above

> > That was /you/. So, how
> > can it be /my/ problem? Ok, the very last time: You accept a
> > situation that
> > doesn't hurt. I don't accept a situation that doesn't make sense.
>
> No, actually you don't accept a situation that DOES makes sense.

I understand that you consider a handler, attached to an event that will
never be raised, makes sense. I don't have to repeat that this is not my
opinion.

> It's your proposal that makes no sense. You want to go to greater
> effort, _both_ with respect to your time spent programming _and_
> with respect to the run-time code execution, to avoid a situation
> that isn't causing a problem in the first place.
>
> > Having
> > event handlers attached to events that will never fire does not
> > make sense
> > (TO ME).
>
> Then leave them there. You still don't need to maintain a list of
> the handlers you have not yet removed.

see above


Well, I would like to be able to take a "snapshot" (metaphorically spoken.
no, it's not about debugging and how I want to do it, it's just a logical
snapshot) of the application at any (consistent) point in time and evaluate
the situation: If I looked at it and you had written the programm,
I would wonder why there are event handlers for events that will never fire.
I wouldn't consider it being a bug (because, we know, "it doesn't hurt"),
but I would consider it being illogical.

I think, everything is said about it, don't you, too? :-)


Armin


Re: Maintain list of attached event handlers (.Net 1.1) by Peter

Peter
Wed Jul 11 18:57:06 CDT 2007

On Wed, 11 Jul 2007 16:24:54 -0700, Armin Zingler <az.nospam@freenet.de>
wrote:

> [...]
> Let me put it this way:
> A basic programming rule that I (and not only I) always obey is: Clean up
> references as soon as I don't need them anymore.

Fine. Remove them then. It doesn't matter. I have said this several
times. I do not know why you insist on dwelling on the issue.

> As, in this case, I don't care whether it takes 1/100 or 1/1,000 of a
> second, how can it be a performance issue? Again, /you/ mentioned
> "performance" first.

I don't understand what the concern of "superfluous things" is if not as
regards to performance. However, fine...I'll take as granted that this is
a question of aesthetics and not performance. Your argument still fails:

> The result of your misinterpretation of why I don't
> want to do superfluous things. It's not for performance reasons. It's
> just
> illogical to do something that does not have to be done.

But it _does_ have to be done. The alternative to is to do something e