PC Review


Reply
Thread Tools Rate Thread

Clearing all event handler attached to an event

 
 
Navaneeth.K.N
Guest
Posts: n/a
 
      21st Oct 2008
Hi all,

Recently I found an interesting question on C# forums about clearing event
handlers of an event. I tried to give it a solution, but failed. I am
interested to know how you guys take this. Here it goes

class Product
{
public event EventHandler ProductChanged;

public Product(string name) {
this.name = name;
}

private string name;
public string Name
{
get { return name; }
set {
name = value;
if (ProductChanged != null)
ProductChanged(this, EventArgs.Empty);
}
}
}

"ProductChanged" event will have many subscribers. I need to clear all these
subscribers from outside "Product" class. Reason is, I am not allowed to
change the "Product" class. I am attaching the event handlers like this,

Product first = new Product("First product");
first.ProductChanged += new EventHandler(first_ProductChanged);

Product second = new Product("Second product");
second.ProductChanged += new EventHandler(second_ProductChanged);

// need to clear the ProductChanged event handlers here
// I can't get the invocation list of "Product.ProductChanged" event here.

is there anyway to achieve this? I think some kind of reflection can do
that, but I am not sure how to go about it.

Any help would be great
 
Reply With Quote
 
 
 
 
Israel
Guest
Posts: n/a
 
      21st Oct 2008
On Oct 20, 11:37*pm, Navaneeth.K.N
<Navaneet...@discussions.microsoft.com> wrote:
> "ProductChanged" event will have many subscribers. I need to clear all these
> subscribers from outside "Product" class. Reason is, I am not allowed to
> change the "Product" class. I am attaching the event handlers like this,


Can you insert a proxy class that looks exactly like the Product class
and contains a reference to it? Then you could manage your own
delegate list via the standard add/remove methods and just subscribe
to the Product event once and when Clear() is called just clear our
your list and unsubscribe to the Product class's event. This would
require that everyone go through the proxy vs. the Product class.


 
Reply With Quote
 
Navaneeth.K.N
Guest
Posts: n/a
 
      21st Oct 2008
Peter,

That was a perfect answer. Thanks for that.

BTW, will unregistered events won't get collected on GC cycles?
 
Reply With Quote
 
Kasim Husaini
Guest
Posts: n/a
 
      22nd May 2009
Hi Peter,

your reply was perfect for a situation where the Subscribed class is only
called from one subscriber.

In my particular situation I have a class A which has few events defined,
Class B, class C ... calls same instance of class A and adds an event handler
individually. I have not control over either Class A or B, C...
I need to clear all the event handlers for the instance of the class A.

Thanks for your support in advance

Kasim Husaini

"Peter Duniho" wrote:

> On Mon, 20 Oct 2008 20:37:01 -0700, Navaneeth.K.N
> <(E-Mail Removed)> wrote:
>
> > [...]
> > // need to clear the ProductChanged event handlers here
> > // I can't get the invocation list of "Product.ProductChanged" event
> > here.
> >
> > is there anyway to achieve this? I think some kind of reflection can do
> > that, but I am not sure how to go about it.

>
> Reflection would not be at all reliable. The field backing the event
> could be modified with reflection, but the name of the field could change
> at any time. Even if you could rely on the name, it's a _really_ bad idea
> to go around mucking about the internals of some class. If you're not
> allowed to modify the class itself to support what you want, then you
> definitely have no business poking around the class's internals. That's
> bad design and a maintenance nightmare.
>
> > Any help would be great

>
> IMHO, the only correct way to do it is to keep your own list of all the
> delegates you've subscribed to the event, so that when you want to remove
> them all, you can do that.
>
> One way to effectively accomplish this is to actually duplicate the event
> yourself in your own class, subscribe a single event handler to the
> Product class, and then forward the event to your own event. When you
> want to clear your own event, you can just set it to null (from within the
> class declaring the event, where you are actually setting the event's
> delegate field to null).
>
> In your case, however, it looks like you want to apply this to the same
> event on multiple instances of the same type. So you'll need to combine
> the above approach with a convenient way to map each instance to the
> delegate used for the event. A Dictionary<> instance can be used for that.
>
> For example (error-checking removed for clarity, uncompiled code):
>
> class MyClass
> {
> private Dictionary<Product, EventHandler> _dictEventForwarder =
> new Dictionary<Product, EventHandler>();
>
> private void _Subscribe(Product product, EventHandler handler)
> {
> EventHandler handlerOld;
>
> if (_dictEventForwarder.TryGetValue(product, out handlerOld))
> {
> handlerOld += handler;
> }
> else
> {
> handlerOld = handler;
> product.ProductChanged += _ForwardingHandler;
> }
>
> _dictEventForwarder[product] = handlerOld;
> }
>
> private void _Unsubscribe(Product product, EventHandler handler)
> {
> EventHandler handlerNew = _dictEventHandler[product] - handler;
>
> if (handlerNew == null)
> {
> _dictEventHandler.Remove(product);
> product.ProductChanged -= _ForwardingHandler;
> }
> else
> {
> _dictEventHandler[product] = handlerNew;
> }
> }
>
> private void _Clear(Product product)
> {
> _dictEventHandler.Remove(product);
> product.ProductChanged -= _ForwardingHandler;
> }
>
> private void _ForwardingHandler(object sender, EventArgs e)
> {
> _dictEventForwarder[(Product)sender](sender, e);
> }
> }
>
> You'll note that to subscribe/unsubscribe handlers to the event, you need
> to go through the special methods for the purpose, rather than doing it
> directly. They wind up subscribing/unsubscribing a single method that
> looks up the appropriate delegate for each instance's event and invokes
> that delegate when the instance's event is raised.
>
> Hope that helps.
>
> Pete
>

 
Reply With Quote
 
Kasim Husaini
Guest
Posts: n/a
 
      22nd May 2009
Hi Peter,

your reply was perfect for a situation where the Subscribed class is only
called from one subscriber.

In my particular situation I have a class A which has few events defined,
Class B, class C ... calls same instance of class A and adds an event handler
individually. I have not control over either Class A or B, C...
I need to clear all the event handlers for the instance of the class A.

Thanks for your support in advance

Kasim Husaini

"Peter Duniho" wrote:

> On Mon, 20 Oct 2008 20:37:01 -0700, Navaneeth.K.N
> <(E-Mail Removed)> wrote:
>
> > [...]
> > // need to clear the ProductChanged event handlers here
> > // I can't get the invocation list of "Product.ProductChanged" event
> > here.
> >
> > is there anyway to achieve this? I think some kind of reflection can do
> > that, but I am not sure how to go about it.

>
> Reflection would not be at all reliable. The field backing the event
> could be modified with reflection, but the name of the field could change
> at any time. Even if you could rely on the name, it's a _really_ bad idea
> to go around mucking about the internals of some class. If you're not
> allowed to modify the class itself to support what you want, then you
> definitely have no business poking around the class's internals. That's
> bad design and a maintenance nightmare.
>
> > Any help would be great

>
> IMHO, the only correct way to do it is to keep your own list of all the
> delegates you've subscribed to the event, so that when you want to remove
> them all, you can do that.
>
> One way to effectively accomplish this is to actually duplicate the event
> yourself in your own class, subscribe a single event handler to the
> Product class, and then forward the event to your own event. When you
> want to clear your own event, you can just set it to null (from within the
> class declaring the event, where you are actually setting the event's
> delegate field to null).
>
> In your case, however, it looks like you want to apply this to the same
> event on multiple instances of the same type. So you'll need to combine
> the above approach with a convenient way to map each instance to the
> delegate used for the event. A Dictionary<> instance can be used for that.
>
> For example (error-checking removed for clarity, uncompiled code):
>
> class MyClass
> {
> private Dictionary<Product, EventHandler> _dictEventForwarder =
> new Dictionary<Product, EventHandler>();
>
> private void _Subscribe(Product product, EventHandler handler)
> {
> EventHandler handlerOld;
>
> if (_dictEventForwarder.TryGetValue(product, out handlerOld))
> {
> handlerOld += handler;
> }
> else
> {
> handlerOld = handler;
> product.ProductChanged += _ForwardingHandler;
> }
>
> _dictEventForwarder[product] = handlerOld;
> }
>
> private void _Unsubscribe(Product product, EventHandler handler)
> {
> EventHandler handlerNew = _dictEventHandler[product] - handler;
>
> if (handlerNew == null)
> {
> _dictEventHandler.Remove(product);
> product.ProductChanged -= _ForwardingHandler;
> }
> else
> {
> _dictEventHandler[product] = handlerNew;
> }
> }
>
> private void _Clear(Product product)
> {
> _dictEventHandler.Remove(product);
> product.ProductChanged -= _ForwardingHandler;
> }
>
> private void _ForwardingHandler(object sender, EventArgs e)
> {
> _dictEventForwarder[(Product)sender](sender, e);
> }
> }
>
> You'll note that to subscribe/unsubscribe handlers to the event, you need
> to go through the special methods for the purpose, rather than doing it
> directly. They wind up subscribing/unsubscribing a single method that
> looks up the appropriate delegate for each instance's event and invokes
> that delegate when the instance's event is raised.
>
> Hope that helps.
>
> Pete
>

 
Reply With Quote
 
ozbear
Guest
Posts: n/a
 
      25th May 2009
On Fri, 22 May 2009 16:50:58 -0700, "Peter Duniho"
<(E-Mail Removed)> wrote:

>On Fri, 22 May 2009 04:49:01 -0700, Kasim Husaini
><(E-Mail Removed)> wrote:
>
>> Hi Peter,
>>

<snip>
>> individually. I have not control over either Class A or B, C...
>> I need to clear all the event handlers for the instance of the class A.

>

<snip>
>
>All that said, you should be sure at the outset that you really need to
>clear the subscribers in the first place. Usually, the class that
>subscribed is the only one that might potentially be affected by remaining
>subscribed, and it should unsubscribe its own handler when it no longer
>needs to be subscribed. The most common scenario I've seen a person claim
>they need to clear out the subscribers is when the class declaring the
>event is being discarded, and in that case, the claim is actually wrong,
>as there's no need to clear the subscribers for an event in a class when
>that class is being discarded; it can be garbage-collected just fine
>without such an operation.
>
>Pete

Pete,
I thought that claim was correct since if X subscribes to Y's event
then X has a reference to Y, and is Y is discarded it would not be
able to be GC'ed because of the reference. You say this is wrong
so clearly my understanding of who has a reference to whom is flawed
and I would appreciate you clearing it up. I recently ran across this
issue in some code I was writing and want to ensure I am both clearing
references I need to and not over-engineering things to account for
issues that (apparently) do not matter.

When X subscribes to Y in, for example,
Y.someevent += X.somehandler;
I thought that in addition to X.somehandler being added to
Y.someevent's invocation list, that X had a reference to Y.

Perhaps my thinking is backwards and that it is actually X that
cannot be GC'ed as long as Y lives because if Y's invocation list
reference back to X, making it somewhat imperative that X
unsubscribe any handlers it has to other classes' events in, say,
X's Dispose method. Or is that also unnecessary?

Any insight gratefully received.

Regards, Oz
--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
ozbear
Guest
Posts: n/a
 
      25th May 2009
On Fri, 22 May 2009 16:50:58 -0700, "Peter Duniho"
<(E-Mail Removed)> wrote:

>On Fri, 22 May 2009 04:49:01 -0700, Kasim Husaini
><(E-Mail Removed)> wrote:
>
>> Hi Peter,
>>

<snip>
>> individually. I have not control over either Class A or B, C...
>> I need to clear all the event handlers for the instance of the class A.

>

<snip>
>
>All that said, you should be sure at the outset that you really need to
>clear the subscribers in the first place. Usually, the class that
>subscribed is the only one that might potentially be affected by remaining
>subscribed, and it should unsubscribe its own handler when it no longer
>needs to be subscribed. The most common scenario I've seen a person claim
>they need to clear out the subscribers is when the class declaring the
>event is being discarded, and in that case, the claim is actually wrong,
>as there's no need to clear the subscribers for an event in a class when
>that class is being discarded; it can be garbage-collected just fine
>without such an operation.
>
>Pete

Pete,
I thought that claim was correct since if X subscribes to Y's event
then X has a reference to Y, and is Y is discarded it would not be
able to be GC'ed because of the reference. You say this is wrong
so clearly my understanding of who has a reference to whom is flawed
and I would appreciate you clearing it up. I recently ran across this
issue in some code I was writing and want to ensure I am both clearing
references I need to and not over-engineering things to account for
issues that (apparently) do not matter.

When X subscribes to Y in, for example,
Y.someevent += X.somehandler;
I thought that in addition to X.somehandler being added to
Y.someevent's invocation list, that X had a reference to Y.

Perhaps my thinking is backwards and that it is actually X that
cannot be GC'ed as long as Y lives because if Y's invocation list
reference back to X, making it somewhat imperative that X
unsubscribe any handlers it has to other classes' events in, say,
X's Dispose method. Or is that also unnecessary?

Any insight gratefully received.

Regards, Oz
--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
ozbear
Guest
Posts: n/a
 
      26th May 2009
On Sun, 24 May 2009 23:00:15 -0700, "Peter Duniho"
<(E-Mail Removed)> wrote:

>On Sun, 24 May 2009 18:49:18 -0700, ozbear <(E-Mail Removed)> wrote:

<snip explanation>
>Pete


Many thanks.

Oz
--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
ozbear
Guest
Posts: n/a
 
      26th May 2009
On Sun, 24 May 2009 23:00:15 -0700, "Peter Duniho"
<(E-Mail Removed)> wrote:

>On Sun, 24 May 2009 18:49:18 -0700, ozbear <(E-Mail Removed)> wrote:

<snip explanation>
>Pete


Many thanks.

Oz
--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Event loop when saving Task item in event handler Mustafa Microsoft Outlook Program Addins 1 8th Aug 2008 06:24 PM
Event Handler that creates adds another event handler kaczmar2@gmail.com Microsoft ASP .NET 1 22nd Feb 2007 07:37 AM
Check if object handles/is hooked up to a certain type of event/event handler nford@vizual.co.uk Microsoft VB .NET 2 14th Jun 2005 11:58 AM
setting a breakpoint in a WinForms event handler... and then getting caught in the event loop. Hazz Microsoft C# .NET 8 14th Feb 2005 08:25 PM
rendering Button inside Render() event, makes it loose its click event handler association sonic Microsoft ASP .NET 1 7th Jan 2005 06:33 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 01:40 PM.