Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / New Users / July 2007

Tip: Looking for answers? Try searching our database.

Maintain list of attached event handlers (.Net 1.1)

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Armin Zingler - 10 Jul 2007 21:40 GMT
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
Peter Duniho - 10 Jul 2007 22:11 GMT
> [...]
> - In a Form's Load event, I recursively process the object tree and  
[quoted text clipped - 9 lines]
> 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
Armin Zingler - 10 Jul 2007 22:48 GMT
> On Tue, 10 Jul 2007 13:40:17 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
[quoted text clipped - 22 lines]
>
> 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
Peter Duniho - 10 Jul 2007 23:36 GMT
> 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  
[quoted text clipped - 3 lines]
> "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
Armin Zingler - 11 Jul 2007 00:15 GMT
> On Tue, 10 Jul 2007 14:48:20 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
[quoted text clipped - 14 lines]
> 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.
[quoted text clipped - 11 lines]
>
> 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
Peter Duniho - 11 Jul 2007 00:50 GMT
> [...]
> You're right, I could do this. Though, isn't it interesting that it is  
[quoted text clipped - 3 lines]
> "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
Armin Zingler - 11 Jul 2007 01:27 GMT
> On Tue, 10 Jul 2007 16:15:14 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
[quoted text clipped - 9 lines]
> 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
Peter Duniho - 11 Jul 2007 01:58 GMT
> 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
Armin Zingler - 11 Jul 2007 04:34 GMT
> > 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
Peter Duniho - 11 Jul 2007 04:53 GMT
> 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.
Armin Zingler - 11 Jul 2007 12:12 GMT
> On Tue, 10 Jul 2007 20:34:48 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
[quoted text clipped - 4 lines]
>
> 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
Peter Duniho - 11 Jul 2007 22:21 GMT
>> 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
[quoted text clipped - 4 lines]
>
> 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
Armin Zingler - 12 Jul 2007 00:24 GMT
[...]
> > > > Why keep listening to events that will never occur?
> > >
[quoted text clipped - 4 lines]
> 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
[quoted text clipped - 9 lines]
> 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
[quoted text clipped - 3 lines]
> 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_
[quoted text clipped - 8 lines]
> 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
Peter Duniho - 12 Jul 2007 00:57 GMT
> [...]
> 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 else  
that otherwise does not have to be done.

You are arguing in favor of a more complicated implementation, so that you  
can avoid something that in theory doesn't have to be done.  But the only  
scenario in which it doesn't have to be done is the one in which you  
complicate the implementation.

The complicated implementation "does not have to be done" any more than  
removing non-existent handlers "does not have to be done".  So, how is it  
that you feel aesthetically it makes more sense to choose doing the thing  
that doesn't have to be done that is more complicated, than to choose the  
thing that doesn't have to be done that is simpler?

> (yes, I know "it
> doesn't hurt" - but doing something that doesn't hurt but that is not
> necessary is still illogical)

It is only illogical if it's true that it's not necessary.  It's necessary  
unless you are intent on doing something else that doesn't otherwise need  
to be done.  I admit, in this context it appears to be unnecessary.  But  
only because you are intent on doing something else that otherwise is  
unnecessary.

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

If I thought that "everything is said about it", I would stop saying  
things.  As long as you continue to present illogical arguments, I will  
continue to point out the flaws in the logic.

Pete
Armin Zingler - 12 Jul 2007 03:25 GMT
> On Wed, 11 Jul 2007 16:24:54 -0700, Armin Zingler
> <az.nospam@freenet.de> wrote:
[quoted text clipped - 7 lines]
> several times.  I do not know why you insist on dwelling on the
> issue.

I'm dwelling on it because you are again saying "it doesn't matter".
Completely wrong. It does matter a lot because it is the precondition for
the whole discussion.

> > 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/
[quoted text clipped - 3 lines]
> not as regards to performance.  However, fine...I'll take as granted
> that this is a question of aesthetics and not performance.

Glad to read this, though I'd call it logic not aesthetics.

> Your
> argument still fails:
[quoted text clipped - 5 lines]
>
> But it _does_ have to be done.

Yes, but not twice. It /has/ already been done. The code has alrady been
written in order to do it /before/. You are ingoring the preconditions. I
explained why they are how they are. If you like to discuss under
different preconditions, do it with whomever because it won't help
/me/. A answer to a question that I did not ask, doesn't help.

>  The alternative to is to do
> something else that otherwise does not have to be done.
>
> You are arguing in favor of a more complicated implementation, so
> that you can avoid something that in theory doesn't have to be done.

Correct. Only "theory" must be replaced by "practice".

>  But the only scenario in which it doesn't have to be done is the
> one in which you complicate the implementation.
[quoted text clipped - 5 lines]
> complicated, than to choose the thing that doesn't have to be done
> that is simpler?

I'm afraid, I don't understand this sentence.

The whole situation can be expressed VB-ish: (no, not executable...)

If immediatelly remove handlers? then    'programmer's decision
   immediatelly remove handlers
   if do more than necessary? then      'programmer's decision
       do more than necessary    'means: detach some handlers a second
                                 'time when closing the form
                                 '(aka illogical)
   else
       maintain a list of remaining handlers
       do only what's necessary  'means: only detach remaining handlers
                                 'when closing the form (aka logical)
   end if
else
   '...
end if

- You are still trying to write the lower Else part, but the first
If-expression has already been evaluated True. That's the precondition.
The corresponding Else part is completely out of interest. Feel free to
discuss it with somebody else but it's not what I am interested in.

- At the second If, you decide for True because you want to avoid the
"maintain a list..." job, whereas I decide for the else block. I do accept
the additional programming work ("maintain...") in order to "do only what's
necessary", whereas you don't.

Our different decisions at the 2nd "If" are caused by differently weighting
the pros and cons. For me, the True block is almost unacceptable whereas you
accept it. To me it is almost unimportant how much work it takes to avoid an
almost unacceptable situation. The additional reason to choose the Else
block was pure technical interest in whether and how it is possible.
Meanwhile I know that it is not possible the way I was looking for,
nevertheless it is possible. Therefore I do it. If it wasn't possible at
all, I would have to swallow the bitter pill and choose the True block.

So, we won't find an agreement because we have different weightings.

> > [...]
> > I think, everything is said about it, don't you, too? :-)
>
> If I thought that "everything is said about it", I would stop saying
> things.  As long as you continue to present illogical arguments,  I
> will continue to point out the flaws in the logic.

No problem. I will repeat my arguments until you got them and see that
your's are illogical. I thought we are grown up enough to avoid this endless
loop. Obviously you are not. Anyways, I won't have to add anything new.

Armin
Peter Duniho - 12 Jul 2007 05:13 GMT
> I'm dwelling on it because you are again saying "it doesn't matter".
> Completely wrong. It does matter a lot because it is the precondition for
> the whole discussion.

It's not.  It never was.  Removing the event handlers in the middle has no  
bearing on what the most efficient way to clean up at the end is.

> Glad to read this, though I'd call it logic not aesthetics.

To make a logical presentation, you have to base it on something.  Logic  
does not exist by itself.  It requires axioms and operators.  You haven't  
stated any axioms yet, so you cannot claim that it's "logic".

My axiomatic goals are performance and memory usage.  You seem to think  
those are not relevant, and I have said that's fine.  However, you haven't  
stated any other axiomatic goals on which you claim to base your  
decisions.  I'm left with aesthetics, simply because that's a viable goal  
in code design at least some of the time and I have not guessed any other  
axiomatic goals you might have.

If you would like to state explicitly the axiomatic goals that guide you  
design, please feel free to do so.  Please do NOT feel free to claim that  
your design is "logical" if you have not yet stated what axiomatic goals  
are used as the starting point for that "logical" conclusion.

>> But it _does_ have to be done.
>
> Yes, but not twice. It /has/ already been done. The code has alrady been
> written in order to do it /before/.

"Before" what?  "It" what?  Your posts would make a lot more sense if you  
would be more explicit about your nouns, instead of using pronouns.  When  
you use pronouns in such an isolated context, I have to make some  
assumptions as to what they mean.  You haven't declared a noun in advance  
of the pronoun, and you are unhappy with the assumptions I am making about  
your intent.  So stop forcing me to make assumptions.

> You are ingoring the preconditions. I
> explained why they are how they are. If you like to discuss under
> different preconditions, do it with whomever because it won't help
> /me/. A answer to a question that I did not ask, doesn't help.

This all started with a very general, vague question about your overall  
goal.  The only two replies you received both said essentially the same  
thing.  If you wanted an answer to a different question, you should have  
been more clear about that.

> [...]
>> The complicated implementation "does not have to be done" any more
[quoted text clipped - 5 lines]
>
> I'm afraid, I don't understand this sentence.

Which sentence don't you understand?  Out of the three that you quoted,  
that is.

> The whole situation can be expressed VB-ish: (no, not executable...)
>
> If immediatelly remove handlers? then    'programmer's decision

This is fine.  It doesn't affect the rest of the discussion.

>     immediatelly remove handlers

Fine.

>     if do more than necessary? then      'programmer's decision

You will have to define "do more than necessary".  By any obvious  
interpretation of the phrase, your conclusion does not result in not doing  
more than necessary.

>         do more than necessary    'means: detach some handlers a second
>                                   'time when closing the form
>                                   '(aka illogical)

The cost of detaching some handlers a second time when closing the form is  
LOWER than the following clause:

>     else
>         maintain a list of remaining handlers

THIS is expensive.  To maintain the list of remaining handlers is "more"  
than to unsubscribe some handlers that have already been unsubscribed.  
You cannot claim that you are doing "more than necessary" by unsubscribing  
some handlers that have already been subscribed while at the same time  
ignoring that you are doing "more than necessary" by maintaining a list of  
remaining handlers.

>         do only what's necessary  'means: only detach remaining handlers
>                                   'when closing the form (aka logical)

Can you not see, in your own way of presenting the situation, that in the  
supposed "do more than necessary" clause, you have only one action, while  
in the supposed "not do more than necessary" clause, you have two?  How is  
doing one thing "more" than doing two things?

>     end if
> else
[quoted text clipped - 3 lines]
> - You are still trying to write the lower Else part, but the first
> If-expression has already been evaluated True. That's the precondition.

No, I am not "still trying to write the lower Else part.  I am trying to  
explain to you that it does not matter what the first "if" condition is.  
The "do the least necessary" answer is still to simply traverse the entire  
data structure when the form closes.

> The corresponding Else part is completely out of interest. Feel free to
> discuss it with somebody else but it's not what I am interested in.

Nor am I.  In nearly every post, I explain to you that it's irrelevant,  
and yet in every reply you come back and tell me that you think I'm still  
talking about it.  How many times do I have to tell you I'm not talking  
about that before you figure out that I'm not talking about that?

> - At the second If, you decide for True because you want to avoid the
> "maintain a list..." job, whereas I decide for the else block. I do  
> accept
> the additional programming work ("maintain...") in order to "do only  
> what's
> necessary", whereas you don't.

I'm not talking about additional programming work.  I'm talking about code  
execution work.  That said, you have MORE of BOTH.  In what way is that  
not "doing more than is necessary"?

> Our different decisions at the 2nd "If" are caused by differently  
> weighting
> the pros and cons.

Only if by "differently weighting the pros and cons" you mean "Armin is  
completely ignoring the cost of maintaining the list of not-yet-removed  
handlers".

You claim the decision is about "not doing more than is necessary", and  
yet your solution is definitely to do more than is necessary.

Now, if you have some other criteria than how much you are "doing", that's  
a different matter.  But you have to state that criteria for me to  
comprehend it.  So far, all you are writing is "doing more than  
necessary", and the way I interpret that is that you are talking either  
about the work in programming, the work of the code executing, or both.  
From what you've written, I have narrowed that down to "the work of the  
code executing", but even by that criteria, your conclusion is wrong.

> For me, the True block is almost unacceptable whereas you
> accept it.

But you have not stated a logically correct reason for it to be that "the  
True block is almost unacceptable".

> To me it is almost unimportant how much work it takes to avoid an
> almost unacceptable situation. The additional reason to choose the Else
> block was pure technical interest in whether and how it is possible.
> Meanwhile I know that it is not possible the way I was looking for,
> nevertheless it is possible. Therefore I do it. If it wasn't possible at
> all, I would have to swallow the bitter pill and choose the True block.

Why is writing less code, and executing less code, a "bitter pill"?  For  
most people, that's a win-win situation.  For some reason, you are  
completely against it.  You spend less time working on the code, it's  
simpler and so less likely to have bugs, and it takes less time to run.  
What's so "bitter" about that?

> So, we won't find an agreement because we have different weightings.

> No problem. I will repeat my arguments until you got them and see that
> your's are illogical.

You have less of an understanding of "logic" than you appear to think you  
have.

> I thought we are grown up enough to avoid this endless
> loop. Obviously you are not. Anyways, I won't have to add anything new.

You already did.  I've replied to it (see above).

Pete
Armin Zingler - 12 Jul 2007 14:06 GMT
As you are not even open to my attempts for an objective explanation of the
situation - which I tried with my VB p-code - the alternatives, their costs
and of why we disagree, I start thinking you are too narrow-minded for a
further discussion. This shall not be my problem anymore.

I don't know why you are not able to accept that we think different, that
we evaluate situations differently, that we call different situations
(un)acceptable, that we consequently decide different, and that we have
a different understanding of logic and clean programming, and we even
use different words (that are well understood in my native language,
sorry) for the same thing. As I've always been appreciated for my
efforts to use clean approaches and for my logical and clean programming
I keep on doing it my way. (I know you consider it all wrong and I know
nothing about everything.)

Though, thanks for participating in this discussion. I'm off...

Armin
Peter Duniho - 12 Jul 2007 18:07 GMT
> As you are not even open to my attempts for an objective explanation of  
> the
> situation - which I tried with my VB p-code

Not only am I open to those attempts, I used them to point out to you the  
fallacy in your argument.  Claiming that I am "not even open" to your  
approach is a non-starter and demonstrably false, as I have at every step  
of the way been happy to discuss the issue in whatever context you've  
offered.

> - the alternatives, their costs
> and of why we disagree, I start thinking you are too narrow-minded for a
> further discussion. This shall not be my problem anymore.

You have chosen a particular design and refuse to consider the possibility  
that a different one might be better, and _I_ am the one who is "too  
narrow-minded"?  That's funny!

> I don't know why you are not able to accept that we think different, that
> we evaluate situations differently,

If by that you mean that I evaluate the situation based on concrete,  
objective criteria, while you are unable to state what your actual design  
goals are, then yes...we do evaluate situations differently.

> that we call different situations (un)acceptable,

I haven't called any situation "unacceptable".  What I have done is point  
out your failure to _explain_ why you consider a particular situation  
"unacceptable".

> that we consequently decide different,

Yes, I am deciding using objective measures while you appear to be using  
intuition.  A classic Meyes-Briggs personality conflict.

> and that we have
> a different understanding of logic and clean programming,

Two people cannot have a "different understanding of logic".  One can  
understand logic while another does not, but logic is inherently rigorous  
and not open to subjective differences of understanding.

Since I have publicly stated the basis and analysis behind my logic, while  
you have not done so, I think it's pretty clear here that I understand  
logic.  I leave the rest of the conclusion to the reader.

> and we even
> use different words (that are well understood in my native language,
> sorry) for the same thing.

I use the words that match those used by Microsoft in their .NET  
documentation.  You use terminology that you made up.  However, whatever  
the case, differences in terminology have NOTHING to do with _this_  
thread.  I understand that you are still sore about being chastised for  
misusing the word "catch", but you need to get over it.  And it has  
nothing to do with this thread.

Pete
John Saunders [MVP] - 12 Jul 2007 03:40 GMT
> [...]
>> > > > Why keep listening to events that will never occur?
[quoted text clipped - 29 lines]
> removement of the reference. Instead, I simply remove it because I don't
> need it anymore. That's the basis rule.

Technology changes. That changes basic rules. This rule, which used to be
basic, needs to be challenged in an environment that includes garbage
collection.

In .NET, it is only rarely a good idea to follow your basic rule.
Signature

John Saunders [MVP]

Armin Zingler - 12 Jul 2007 12:59 GMT
> > Let me put it this way:
> > A basic programming rule that I (and not only I) always obey is:
[quoted text clipped - 10 lines]
>
> In .NET, it is only rarely a good idea to follow your basic rule. --

Well, in the German VB.Net group, there were 4 people that agree with me in
this point (4 out of 4). Even the GC doesn't collect objects that are still
referenced. It is common practice and considered clean programming to
remove references to objects that are not needed anymore. Maybe you haven't
heard of it yet.

Armin
John Saunders [MVP] - 12 Jul 2007 14:56 GMT
>> > Let me put it this way:
>> > A basic programming rule that I (and not only I) always obey is:
[quoted text clipped - 18 lines]
> remove references to objects that are not needed anymore. Maybe you
> haven't heard of it yet.

That's it, I'm sure.
Signature

John Saunders [MVP]

Damien - 12 Jul 2007 15:57 GMT
> > > Let me put it this way:
> > > A basic programming rule that I (and not only I) always obey is:
[quoted text clipped - 18 lines]
>
> Armin

Hi Armin,

Sorry to butt in, possibly with more unwelcome advice. Have you
considered the fact that it used to be best practice to always free
memory as soon as possible, but that now under the GC, the freeing of
memory is done when it is required/when it is convenient.

Now, apply this analogy to the cleaning up of your event handlers.
You're "cleaning up as soon as possible". Peter and John are
advocating "cleaning up when it's convenient".

Let's also consider the fact that, in this case, you have to perform
this clean up in order to ensure that the overall system continues to
run efficiently (no "orphan" objects attached to live objects). In
this case, you have to ensure that resources get cleaned up no matter
what - in the face of possible exceptions and the like - which would
surely lead to you using John/Peters suggestion anyway (possibly with
a comment above it, if you think it's going to trip you/others up
later such as "Of course, some of these may have already been
removed").

Damien

PS - your survey of 4 people on the German newsgroup about which
option would be advocated may or may not be significant - it may come
down to how you've phrased the problem. Thus far, on this newsgroup,
you've got 2 knowledgable individuals recommending a different
approach. I've stayed silent thus far because I agreed wholeheartedly
with what they were saying.
Armin Zingler - 12 Jul 2007 18:48 GMT
> On Jul 12, 12:59 pm, "Armin Zingler" <az.nos...@freenet.de> wrote:
> >
[quoted text clipped - 25 lines]
>
> Sorry to butt in, possibly with more unwelcome advice.

Nah, no problem. :-) Advice is always welcome.

> Have you
> considered the fact that it used to be best practice to always free
> memory as soon as possible, but that now under the GC, the freeing
> of memory is done when it is required/when it is convenient.

I know this, but if you don't release references, the GC does not even has
the /chance/ to free memory. That's why it is common practice to release
references as soon as possible. Not in order to free memory immediatelly but
to make it possible. (But I don't go as far as some people that even set
/local/ variables to Nothing at the end of a procedure. That's too much for
me).

> [...]

I'm afraid, there is nothing new I can add. Instead, I can offer a (IMO)
good comparison:

Imagine, you know 50 people. From time to time you lend things to them.
Every 12/31 you want all lended things back. You have two choices:

a) At 12/31, call all the people and tell everyone to give the things back.
This means, calling also those people that have already given everything
back. It doesn't hurt to call them, but I call it "illogical" (please
replace it by the word of your choice). The phone costs or the time that
it takes is not an issue, but simply doing it although it is not necessary
is IMO not acceptable.

b) Everyone who borrows anything is put on a list. As soon as it's given
back, he is removed from the list. At 12/31, only the people on the list are
called.

You won't be suprised that I favor b) even if I have to maintain a list. I
do this because I consider it the "cleaner" approach.

I guess you favor a) ? :-) I accept this opinion - I just don't want to be
handled like an idiot because mine is different.

> PS - your survey of 4 people on the German newsgroup about which
> option would be advocated may or may not be significant - it may
> come down to how you've phrased the problem.

The question in the other group was only about "release references as soon
as possible". I referred to John's mentioning of the "basic rule" (which is
the immediate release). I only asked there to insure myself that I was not
seeing things throughout the past years. :-)

> Thus far, on this
> newsgroup, you've got 2 knowledgable individuals recommending a
> different
> approach. I've stayed silent thus far because I agreed
> wholeheartedly with what they were saying.

Though, thanks for your opinion. I like the way you express it. Thank you!
(and this is not ironic)

Armin
Peter Duniho - 12 Jul 2007 19:11 GMT
> [...]
> Imagine, you know 50 people. From time to time you lend things to them.
[quoted text clipped - 17 lines]
> I
> do this because I consider it the "cleaner" approach.

Your analogy fails because a phone call is far more expensive than writing  
something on a list.  Also, you are dealing with numbers that are so small  
that managing the list is relatively easy, even for a human being.

Those characteristics do not translate to your problem.  In particular,  
the unsubscribing operation is incredibly _inexpensive_.  Much less  
expensive than the act of maintaining _any_ list, however small.  And  
while maintaining your list of subscribed handlers isn't too bad as long  
as the number is small, code should be scalable and your approach will  
incur greater and greater performance penalties as the number of nodes in  
your tree grows.

> I guess you favor a) ? :-) I accept this opinion - I just don't want to  
> be
> handled like an idiot because mine is different.

Nobody is treating you like an idiot.  Don't confuse the act of point out  
your mistakes as treating you like an idiot.

> The question in the other group was only about "release references as  
> soon
> as possible".

Then that is entirely inapplicable to the point I have been making.  As I  
have stated each time you bring it up: you may unsubscribe the event  
handlers as soon as you like.  I wouldn't bother with it myself, but it's  
not a fundamental design problem.

So, the answer you receive in the other group is entirely irrelevant to  
the point I am making.

Pete
Armin Zingler - 13 Jul 2007 01:22 GMT
A friend told me: "I am adding zero to zero all day long".
I asked: "Why do you do this?"
He answered: "Because it goes sooo quick and it doesn't hurt!"
Me: "Ummmm.... yes, that makes a LOT of sense......."
Me: "But why don't you visit a psychiatrist to stop this?"
He said: "It costs!"
Me: "Ah, I see...But wouldn't it be nice to stop this even if it costs?"
He said: "But why? It goes so quick and it doesn't hurt!"

I stopped trying to convince him.
Peter Duniho - 13 Jul 2007 03:37 GMT
> A friend told me: "I am adding zero to zero all day long".
> [...]
>
> I stopped trying to convince him.

So you're trying to say I should stop trying to convince you?
Damien - 13 Jul 2007 08:10 GMT
> > Hi Armin,
>
[quoted text clipped - 13 lines]
> /local/ variables to Nothing at the end of a procedure. That's too much for
> me).

Okay. I was just trying to highlight the fact that what was once a
best practice of "release immediately" (with respect to freeing
memory) is now a) not followed, and b) because of the GC design, not
even possible - it's all entirely under the GCs control, and it
follows a different strategy.

> > [...]
>
[quoted text clipped - 20 lines]
> I guess you favor a) ? :-) I accept this opinion - I just don't want to be
> handled like an idiot because mine is different.

I guess what Peter especially is trying to get you to focus on is the
fact that all strategies for release have attendent overheads. Have
you ever done any robust COM programming in a C derived language? It's
amazing how complex it is to just make sure your reference counting
code is correct, and handles the edge cases - and that was because the
COM model was based around the "release as soon as possible" approach.

I know you've stated you're not looking at this from a performance
perspective, but from a "clean code" perspective. In Peter's code, we
can see 1 operation, in 1 place, possibly with the comment "Some of
these may have already been removed", which goes through the whole
tree and removes all of the handlers. I can go and look at that one
chunk of code, and know that I am *sure* that all of the handlers are
being removed when the form closes.

Contrast this with your solution. I have to read this "same" chunk of
code, and see that it is removing only those handlers which haven't
been removed. But I then need to go and review each handler, and
verify that it is removing itself correctly. And I then need to
examine all of the list maintenance procedures, and ask myself
questions such as "is this list operation thread safe?", "Does it need
to be?". Only after I've done all of that would I be as confident that
your solution is removing all of the handlers.

And even if I had verified your solution, I'd probably still go back
to the final "chunk" which does the cleanup and remove the list
checks, and let it remove all of the handlers (again, adding the
comment if you so wish), because a) I know that the removal code is
cheeper to run than the list checkup code (okay, that is a performance
argument), BUT b) because I'm going to use a belt and braces approach.

Sorry - I don't know if you know or understand the phrase "belt and
braces". I don't know if there's a German equivalent. It refers to the
practice of ensuring something happens (in this case, your trousers
staying up) by the use of more than method (using a belt, and also
using braces).

This post turned a bit epic. Apologies.

Damien
Armin Zingler - 13 Jul 2007 12:29 GMT
> On Jul 12, 6:48 pm, "Armin Zingler" <az.nos...@freenet.de> wrote:
> > > Hi Armin,
[quoted text clipped - 21 lines]
> even possible - it's all entirely under the GCs control, and it
> follows a different strategy.

I know this all. I already wrote that it is not done to release
memory immediatelly, but to give the GC the /chance/ to clean up objects.
Without releasing unrequired references, objects will /never/ be destroyed.

> > > [...]
> >
[quoted text clipped - 30 lines]
> that was because the COM model was based around the "release as soon
> as possible" approach.

I've heard of it. :-) Fortunatelly, in VB classic it was simpler to handle,
though I know what was going on under the hood (addref/releaseref...). I
like the GC approach more.

> I know you've stated you're not looking at this from a performance
> perspective, but from a "clean code" perspective. In Peter's code,
> we can see 1 operation, in 1 place, possibly with the comment "Some
> of these may have already been removed",

Right. The very last sentence is the reason why it is not an acceptable
solution (for me). I'm afraid, I can not add anything new to the rest of
your posting.

Doing it Peter's way is /intentionally/ writing code that /intentionally/ is
sometimes doing things that do not have to be done. Even if those
superfluous things are "inexepensive" and "don't hurt" (just like adding
zero to zero which also doesn't make sense...), why should I decide for
intentionally writing this code? That's what I call an "illogical" decision
(you may call it different, of course). I don't want to write illogical
code. I accept writing more code in order to prevent me from writing
illogical code - yes, even if it costs. Sometimes the logical way is longer.
Peter's solution has such a big drawback that it is not acceptable for me.
You probably don't consider it being a "big" drawback, but for me it so big
that it is /unacceptable/.

/As a consequence/, I /had to/ find a way to avoid the situation above.
Assuming this, the next decision was to "maintain a list...". That's an
obvious decision (because if you want to store an unknown number of items,
a list/arraylist/whatever is what a programmer does).

What has always been ignored in this thread is the 2nd reason why I asked
here: As an experienced programmer - I guess all the people in this
thread are - I came to the point where I wondered how to store a certain
piece of information. Programmers store and retrieve information all day
long, so we know how it works. But in this case I did not know how to do
it: How can I store information in variables that can later be used with
the Addhandler/Removehandler keyword? (in addition: without handling each
object type and event individually to be able to maintain it in a single
list; meanwhile I know that it is not possible and I accepted it)

  -> This is just a technical question <-

Don't you sometimes want to learn things just for the sake of learning?
It doesn't matter whether you will ever use the knowledge, but you are just
interested in it. In this case, I felt that the question was very
interesting because i haven't had the case not to know how to store a
piece of information for a long time. Therefore I asked here.

Armin
Damien - 13 Jul 2007 13:55 GMT
> > On Jul 12, 6:48 pm, "Armin Zingler" <az.nos...@freenet.de> wrote:
> > > > Hi Armin,
[quoted text clipped - 85 lines]
> You probably don't consider it being a "big" drawback, but for me it so big
> that it is /unacceptable/.

I'll try to put my point more briefly than last time. Because having 1
small piece of code where I can see exactly what is happening is
easier to comprehend, and be sure it is correct, than a large number
of blocks of code, through the source, which all have to be read and
understood before you can be sure that the code is doing the right
thing.

You example of adding zero being a wasted operation? How would you
write the following function:

Function ABC takes two arrays (which most both be 1 dimensional arrays
of integers with the same length). It must return a new array, of the
same length as the inputs, where the value at each position is the sum
of the input values at the same position. (Exception throwing code for
length mis-match omitted).

Option 1:

 Public Function ABC(ByVal ar1() As Integer, ByVal ar2() As Integer)
As Integer()
   Dim out(ar1.GetUpperBound(0)) As Integer

   For i As Int32 = 0 To ar1.GetUpperBound(0)
     out(i) = ar1(i) + ar2(i)
   Next
   Return out
 End Function

Option 2:

 Public Function ABC(ByVal ar1() As Integer, ByVal ar2() As Integer)
As Integer()
   Dim out(ar1.GetUpperBound(0)) As Integer

   For i As Int32 = 0 To ar1.GetUpperBound(0)
     If ar1(i) = 0 Then
       If ar2(i) = 0 Then
         out(i) = 0
       Else
         out(i) = ar2(i)
       End If
     Else
       If ar2(i) = 0 Then
         out(i) = ar1(i)
       Else
         out(i) = ar1(i) + ar2(i)
       End If
     End If
   Next
   Return out
 End Function

I hope you'll stick to your guns and choose Option 2, since Option 1
sometimes performs addition operations it doesn't have to.

[snip to end]
>    -> This is just a technical question <-
>
[quoted text clipped - 5 lines]
>
> Armin

Absolutely. I love learning new things. I frequently don't know the
answer to questions people pose on these newsgroups. But if the
question is interesting, I'll sometimes spend some time looking into
the question. Even if I can't then answer the question, I'll usually
have learnt something new. Or I'll provide half an answer and invite
others to extend it to where I cannot - and learn from that.

The day I stop learning is the day I die.

Damien
Armin Zingler - 13 Jul 2007 17:38 GMT
> > Right. The very last sentence is the reason why it is not an
> > acceptable solution (for me). I'm afraid, I can not add anything
[quoted text clipped - 17 lines]
> 1 small piece of code where I can see exactly what is happening is
> easier to comprehend,

I would have my problems to explain the, at first sight, more comprehensive
code to somebody else. If my boss (although I don't have one...) looked at
it, he would probably ask me: "You are removing handlers immediatelly,
right?". Me: "Right". He: "At the end, you are removing also those handlers
that already have been removed. Maybe all handlers have already been
removed, though you are really removing all handlers twice? It doesn't hurt
but it also doesn't make sense, so change this!". I'll change the code
because I see that he is right - even if it is extra work.

I think, code must be explainable. Code that sometimes does superfluous
things is not explainable.

> and be sure it is correct, than a large number
> of blocks of code, through the source, which all have to be read and
> understood before you can be sure that the code is doing the right
> thing.

I don't have a problem in understanding the code. It is not an argument to
not write code because it will have to be understood by anybody in the
future because this is true for /any/ code. If the code has to be written,
it has to be done. (I know that you think it doesn't have to be written).

> You example of adding zero being a wasted operation? How would you
> write the following function:
[quoted text clipped - 3 lines]
> I hope you'll stick to your guns and choose Option 2, since Option 1
> sometimes performs addition operations it doesn't have to.

Good example that makes me think about it. I would choose Option 1.
The analogy fails because your Option 2 translated to my case would
have to be (pseudo code):

for each item in list
   if item.handlerisattached then
       item.removehandler
   end if
next item

That's what I do /not/. Would be even too much for me (just as too much as
"if a isnot nothing then a = nothing").

I apologize that I won't discuss this example additionally, because I really
want to come to an end, primarily because my solution runs since...

> >    -> This is just a technical question <-
> > [...]
[quoted text clipped - 6 lines]
>
> The day I stop learning is the day I die.

I completely agree.

Armin
Rory Becker - 12 Jul 2007 18:54 GMT
> PS - your survey of 4 people on the German newsgroup about which
> option would be advocated may or may not be significant - it may come
> down to how you've phrased the problem. Thus far, on this newsgroup,
> you've got 2 knowledgable individuals recommending a different
> approach.

> I've stayed silent thus far because I agreed wholeheartedly
> with what they were saying.

+1

Appologies for not adding much to this except my vote, but Damien has said
it all quite nicely.

--
Rory
Peter Duniho - 12 Jul 2007 19:04 GMT
> Sorry to butt in, possibly with more unwelcome advice. Have you
> considered the fact that it used to be best practice to always free
> memory as soon as possible, but that now under the GC, the freeing of
> memory is done when it is required/when it is convenient. [...]

As you can see (from his reply), the question of whether or not to  
unsubscribe the event handlers as soon as they can be continues to  
distract Armin from the real issue: how to clean up when the form is  
closed.

IMHO, it would be better to leave off the question about whether to  
unsubscribe the handlers as they are used.  I agree (obviously) that  
there's no need to unsubscribe the handlers except at the end.  But since  
it's still more efficient to simply traverse the tree an unsubscribe all  
of the events, even those that have already been unsubscribed, the  
question of whether or not he unsubscribes them as they are used is just a  
red herring.

The real question here IMHO is whether to make any attempt to track which  
event handlers have been unsubscribed.  I take as granted (because Armin  
insists) that the event handlers _will_ be unsubscribed as they are used,  
and I still come to the conclusion that a simple tree traversal at the end  
to unsubscribe all of the events is superior to any sort of scheme  
attempting to track what's left to unsubscribe.

I also note that even if one is going to track what's left to unsubscribe,  
Armin's solution is inefficient and far too complex.  But that's yet  
another issue, and since I don't agree that the tracking should be done in  
the first place, I won't waste much time talking about that.  :)

Pete
John Saunders [MVP] - 11 Jul 2007 00:08 GMT
> Hi,
>
[quoted text clipped - 11 lines]
> - 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.
Signature

John Saunders [MVP]

Armin Zingler - 11 Jul 2007 00:57 GMT
> "Armin Zingler" <az.nospam@freenet.de> wrote in message
> news:eEhlPQzwHHA.3364@TK2MSFTNGP02.phx.gbl...
[quoted text clipped - 19 lines]
> 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
Peter Duniho - 11 Jul 2007 01:53 GMT
> 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 they  
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 about  
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 the  
objects for which you want to subscribe to an event or events.  So, do the  
same enumeration when you want to unsubscribe, and unsubscribe from every  
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  
[quoted text clipped - 6 lines]
> 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 nothing  
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, just  
as you traversed the tree and subscribed to start with.

> Though, it is still interesting for me that I can not store the  
> information
[quoted text clipped - 3 lines]
> 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 is):

    public event MyHandlerType myevent;

and then later do this:

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

so that even later you could do this:

    *pevent -= 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 = ...;

    raiser.myevent += MyEventHandler;

and then even later do this:

    raiser.myevent -= MyEventHandler;

The two are basically equivalent.  The only difference is that in one case  
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 than  
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 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.

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

Pete
Peter Duniho - 11 Jul 2007 02:43 GMT
> [...]
>> It shows that I currently have to handle each event individually. It  
[quoted text clipped - 3 lines]
> 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
Armin Zingler - 11 Jul 2007 04:43 GMT
> 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
[quoted text clipped - 5 lines]
>
> 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#]
> [...]
[quoted text clipped - 6 lines]
> 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:
[quoted text clipped - 16 lines]
> 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
Peter Duniho - 11 Jul 2007 05:27 GMT
> 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
[quoted text clipped - 11 lines]
>     [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.
[quoted text clipped - 11 lines]
>
> 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  
[quoted text clipped - 3 lines]
> 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
[quoted text clipped - 3 lines]
> 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
[quoted text clipped - 3 lines]
> 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
Armin Zingler - 11 Jul 2007 12:23 GMT
> [...]

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