Stupid question about eventHandlers, or objects in general

  • Thread starter Thread starter RvGrah
  • Start date Start date
R

RvGrah

I'm using the Activated event of my form to run a database query in a
backroundWorker, and want to dismiss the call after the first time the
form is activated. Based on some excellent advice in an earlier post,
instead of maintaining a flag, I'm unsubscribing to this eventHandler.
My question is, why is this functional:

this.Activated -= new
System.EventHandler(Form1_Activated);

instead of:
this.Activated -= System.EventHandler(Form1_Activated);

Why would it be "new" when the event was newed in the form's creation
code? Don't you end up with a reference to a new delegate rather that
unsubscribing to the original?

Please enlighten me, all you smarter than me types. ;-)

Bob Graham
 
RvGrah said:
I'm using the Activated event of my form to run a database query in a
backroundWorker, and want to dismiss the call after the first time the
form is activated. Based on some excellent advice in an earlier post,
instead of maintaining a flag, I'm unsubscribing to this eventHandler.
My question is, why is this functional:

this.Activated -= new
System.EventHandler(Form1_Activated);

instead of:
this.Activated -= System.EventHandler(Form1_Activated);

if you're using C# 2.0 doesn't this work :

Activated -= Form1_Activated;

?
 
You're absolutely right! It looks a lot more intutitive as well, in
that funky terse c kind of way.

Still curious about why the "newing" in the first approach doesn't
cause a malfunction.

Thanks, Bob
 
RvGrah said:
I'm using the Activated event of my form to run a database query in a
backroundWorker, and want to dismiss the call after the first time the
form is activated. Based on some excellent advice in an earlier post,
instead of maintaining a flag, I'm unsubscribing to this eventHandler.
My question is, why is this functional:

this.Activated -= new
System.EventHandler(Form1_Activated);

instead of:
this.Activated -= System.EventHandler(Form1_Activated);

Why would it be "new" when the event was newed in the form's creation
code? Don't you end up with a reference to a new delegate rather that
unsubscribing to the original?

Please enlighten me, all you smarter than me types. ;-)

The Delegate.Remove removes delegates based on equality, not reference
identity. Two delegates which use the same method and have the same
target object (for instance methods) are considered equal.
 
RvGrah said:
You're absolutely right! It looks a lot more intutitive as well, in
that funky terse c kind of way.

Still curious about why the "newing" in the first approach doesn't
cause a malfunction.

See my other post for that. Note that using

Activated -= Form1_Activated;

will generate *exactly* the same IL as

Activated -= new EventHandler(Form1_Activated);
 
The += and -= are implemented as 'add' and 'remove' methods of the event
handler ("Activated").

It's basically a linked list of target delegates that are to be called.

+= adds the delegate to the end of the list.

-= checks the list to see if a delegate exists in it, using a .Equals
call to compare delegates, rather than an .ReferenceEquals(). This means
delegates 'match' if the target method and instance are the same.

So it works :-)
 
Thank you Jon and AJ

I feel a bit wiser now. I do understand the concept of referencing the
same object from two different "pointers" so to speak, so removing the
object removes the same object either way.

Bob
 
RvGrah said:
Thank you Jon and AJ

I feel a bit wiser now. I do understand the concept of referencing the
same object from two different "pointers" so to speak, so removing the
object removes the same object either way.

Well, there are two different objects here - different but equal. It's
not like you have two references to the same object.
 
Looking at your comment, I re-read AJ's post above, and now I
understand better the difference between .Equals and .ReferenceEquals.

I also realize some code I use in places is faulty. For instance in
places where I have more than one control using the same event
handler, I sometimes want to act on all the other controls and not the
one that called the procedure. So I cast the sender to the type:

Button b = sender as Button;

for each (button bt in myButtons)
if (!bt.Equals(b)) .... do stuff

(pseudo code sort of, may not be syntactically accurate)

This seems to work fine. Is it because all the button's properties
match exactly that it successfully *doesn't* act on the sender? Should
I be using .ReferenceEquals?

Bob
 
In *general* for classes, Equals works by comparing the reference;
this is the case with Button - so it has nothing to do with
properties, but rather your "!bt.Equals(b)" works because they are
different button instances.

The delegate comment in AJs post is because delegates work
differently; for the purposes of event [un]subscription, they are
considered equal if (as already started) the instance and method both
match. So even though you might be unsubscribing with a "new
EventHandler(this.SomeMethod)", this has the effect of looking at the
existing list (in reverse order, btw), removing the first (or last,
depending on your view) event-handler for the same object and method.

Marc
 
Marc said:
In *general* for classes, Equals works by comparing the reference;
this is the case with Button - so it has nothing to do with
properties, but rather your "!bt.Equals(b)" works because they are
different button instances.

That said, if the goal of the code is to test reference equality, it is
probably better to call ReferenceEquals directly, rather than relying on
that being the default behavior of the class.

If nothing else, it makes the code more readable and thus easier to
maintain correctly.

Pete
 
I agree entirely (in fact, I had this same conversation very
recently) - my aim was to explain to Bob why his current Button test
was working. But I missed his final question, and I agree: if the
intent is to check that two object variables refer to the same
instance, then ReferenceEquals is the way to go.

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top