469,579 Members | 1,627 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,579 developers. It's quick & easy.

Clearing all event handler attached to an event

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
Oct 21 '08 #1
4 7646
On Mon, 20 Oct 2008 20:37:01 -0700, Navaneeth.K.N
<Na*********@discussions.microsoft.comwrote:
[...]
// 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
Oct 21 '08 #2
On Oct 20, 11:37*pm, Navaneeth.K.N
<Navaneet...@discussions.microsoft.comwrote:
"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.
Oct 21 '08 #3
Peter,

That was a perfect answer. Thanks for that.

BTW, will unregistered events won't get collected on GC cycles?
Oct 21 '08 #4
On Tue, 21 Oct 2008 11:18:22 -0700, Navaneeth.K.N
<Na*********@discussions.microsoft.comwrote:
Peter,

That was a perfect answer. Thanks for that.

BTW, will unregistered events won't get collected on GC cycles?
I don't know what that means. What's an "unregistered event"? Why
wouldn't one get collected? All the usual GC rules apply...if the
instance is reachable, it won't be collected, otherwise it will.

Pete
Oct 21 '08 #5

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Beth | last post: by
4 posts views Thread by eggie5 | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.