473,386 Members | 1,823 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Delegates and Events confusion

I have a class (let's call it ClassA) that I've written which has events.
In another class (let's call it ClassB) I create a collection of ClassA
objects. In a third class (ClassC) I create a reference to some of the
ClassA objects created in ClassB. In ClassC I hook into the ClassA events
with a foreach loop so that I hook each object. The code is something like
this:
class ClassC {
void SomeMethod()
{
foreach (ClassA item in ClassACollection)
{
item.MyEvent += new EventHandler(item_MyEvent);
}
}
}

Objects of type ClassC keep getting created and deleted, but the objects of
ClassA that it references stay in memory. Therefore, every time I load a
new instance of ClassC the event gets hooked again. What I'm seeing is that
I fire the event once but I end up getting it raised in the code that
responds to it (item_MyEvent method) for every time it was added when I only
want it to get caught once.

How can I be sure that I only add the handler to the event once for each
item? Since the code is in ClassC it's not allowed to inspect the
ClassA.MyEvent to see if something's already hooked to it.

I hope this makes sense. Creating a repro case wouldn't make sense here
because it's my application logic that's causing the problem.

Thanks.
Nov 16 '05 #1
15 2060
Are you unsubscribing the event when you remove the instances of Class C
from memory?

If you subscribe to an event and do not unsubscribe, the subscriber will be
held in memory until the event publisher (class A) is collected.

Here's why:
A delegate has a member called Target. Target is a reference to the
subscriber (Class C). When you add the event, the publisher holds a
reference to the delegate which in turn holds a reference to the subscriber,
so C is held in memory. The graph looks like this:

A ---> EventDelegate ---->C

So, the reason that you are getting multiple event fires is that you have
more instances of C in memory than you think that you do.

What you probably want to do is to keep track of all of the event
subscriptions that C makes and have C implement IDispose. When you are
ready to kill C, call its Dispose method. Inside the Dispose, unsubscribe
from all of the events that you are subscribed to.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:uV*************@TK2MSFTNGP09.phx.gbl...
I have a class (let's call it ClassA) that I've written which has events.
In another class (let's call it ClassB) I create a collection of ClassA
objects. In a third class (ClassC) I create a reference to some of the
ClassA objects created in ClassB. In ClassC I hook into the ClassA events
with a foreach loop so that I hook each object. The code is something like this:
class ClassC {
void SomeMethod()
{
foreach (ClassA item in ClassACollection)
{
item.MyEvent += new EventHandler(item_MyEvent);
}
}
}

Objects of type ClassC keep getting created and deleted, but the objects of ClassA that it references stay in memory. Therefore, every time I load a
new instance of ClassC the event gets hooked again. What I'm seeing is that I fire the event once but I end up getting it raised in the code that
responds to it (item_MyEvent method) for every time it was added when I only want it to get caught once.

How can I be sure that I only add the handler to the event once for each
item? Since the code is in ClassC it's not allowed to inspect the
ClassA.MyEvent to see if something's already hooked to it.

I hope this makes sense. Creating a repro case wouldn't make sense here
because it's my application logic that's causing the problem.

Thanks.

Nov 16 '05 #2
Thanks. I figured that I needed to unsubscribe in some way but since I
wasn't storing an internal reference to the subscriber. I added the code
like the following and it solved the problem but I don't really understand
why:

item.MyEvent -= new EventHandler(item_MyEvent);

This just seems really odd to me. If the += assignment adds a refernece to
a new event handler it seems that handler would be a different object than
the one created with the new operator in the -= assignment. I could see
something like this working:
EventHandler eh = new EventHandler (item_MyEvent);
item.MyEvent += eh;
....then later...
item.MyEvent -= eh;
I can see that working because it's the same object, but when I use the new
keyword twice don't I have two unique references?

- Rhy
"J.Marsch" <je****@ctcdeveloper.com> wrote in message
news:%2***************@TK2MSFTNGP12.phx.gbl...
Are you unsubscribing the event when you remove the instances of Class C
from memory?

If you subscribe to an event and do not unsubscribe, the subscriber will
be
held in memory until the event publisher (class A) is collected.

Here's why:
A delegate has a member called Target. Target is a reference to the
subscriber (Class C). When you add the event, the publisher holds a
reference to the delegate which in turn holds a reference to the
subscriber,
so C is held in memory. The graph looks like this:

A ---> EventDelegate ---->C

So, the reason that you are getting multiple event fires is that you have
more instances of C in memory than you think that you do.

What you probably want to do is to keep track of all of the event
subscriptions that C makes and have C implement IDispose. When you are
ready to kill C, call its Dispose method. Inside the Dispose, unsubscribe
from all of the events that you are subscribed to.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:uV*************@TK2MSFTNGP09.phx.gbl...
I have a class (let's call it ClassA) that I've written which has events.
In another class (let's call it ClassB) I create a collection of ClassA
objects. In a third class (ClassC) I create a reference to some of the
ClassA objects created in ClassB. In ClassC I hook into the ClassA
events
with a foreach loop so that I hook each object. The code is something

like
this:
class ClassC {
void SomeMethod()
{
foreach (ClassA item in ClassACollection)
{
item.MyEvent += new EventHandler(item_MyEvent);
}
}
}

Objects of type ClassC keep getting created and deleted, but the objects

of
ClassA that it references stay in memory. Therefore, every time I load a
new instance of ClassC the event gets hooked again. What I'm seeing is

that
I fire the event once but I end up getting it raised in the code that
responds to it (item_MyEvent method) for every time it was added when I

only
want it to get caught once.

How can I be sure that I only add the handler to the event once for each
item? Since the code is in ClassC it's not allowed to inspect the
ClassA.MyEvent to see if something's already hooked to it.

I hope this makes sense. Creating a repro case wouldn't make sense here
because it's my application logic that's causing the problem.

Thanks.


Nov 16 '05 #3
It IS confusing that you're *subtracting* a *new* object, but that IS the correct syntax. Remember that the 'new' event handler that you're subtracting is actually (in all probability) a reference to a specific instance's member function, so it's basically just saying 'this member function of this instance doesn't want to receive this event any more.' To tell the compiler that, all it needs is *ANY* object whose type is a delegate to that member function, and it will understand - presumably this was the least confusing (albeit more than slightly lateral) way of implementing this syntax.

Nov 16 '05 #4
Beeeeeeeeeeeeves <Be**************@discussions.microsoft.com> wrote:
It IS confusing that you're *subtracting* a *new* object, but that IS
the correct syntax. Remember that the 'new' event handler that you're
subtracting is actually (in all probability) a reference to a
specific instance's member function, so it's basically just saying
'this member function of this instance doesn't want to receive this
event any more.' To tell the compiler that, all it needs is *ANY*
object whose type is a delegate to that member function, and it
willunderstand - presumably this was the least confusing (albeit more
than slightly lateral) way of implementing this syntax.


Bear in mind, however, that there are two parts to a delegate - the
method itself, and the target object. So doing

Foo f = new Foo();
x.SomeEvent += new SomeDelegate(f.Something);
x.SomeEvent -= new SomeDelegate(f.Something);

will add and then remove the handler.

x.SomeEvent += new SomeDelegate (new Foo().Something);
x.SomeEvent -= new SomeDelegate (new Foo().Something);

will fail to remove the handler it's added, as the two delegates in
question aren't equal.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #5
To answer that question, we can fire up Reflector
http://www.aisto.com/roeder/dotnet/ and look at the definition of the
Delegate class. In it, we find that the the Equals() method has been
overridden. Two delegates are considered equal if they both target the same
object instance and the same method within that object instance.

So:
event1 = new EventHandler(item_MyEvent);
event2 = new EventHandler(item_MyEvent);

?event1.Equals(event2); // true

When you execute this:
item.MyEvent -= new EventHandler(item_MyEvent);

The publisher goes looking for a delegate that it is holding that is equal
to the one that you passed, and it finds the one that you passed in the +=
statement.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:Os**************@TK2MSFTNGP12.phx.gbl...
Thanks. I figured that I needed to unsubscribe in some way but since I
wasn't storing an internal reference to the subscriber. I added the code
like the following and it solved the problem but I don't really understand
why:

item.MyEvent -= new EventHandler(item_MyEvent);

This just seems really odd to me. If the += assignment adds a refernece to a new event handler it seems that handler would be a different object than
the one created with the new operator in the -= assignment. I could see
something like this working:
EventHandler eh = new EventHandler (item_MyEvent);
item.MyEvent += eh;
...then later...
item.MyEvent -= eh;
I can see that working because it's the same object, but when I use the new keyword twice don't I have two unique references?

- Rhy
"J.Marsch" <je****@ctcdeveloper.com> wrote in message
news:%2***************@TK2MSFTNGP12.phx.gbl...
Are you unsubscribing the event when you remove the instances of Class C
from memory?

If you subscribe to an event and do not unsubscribe, the subscriber will
be
held in memory until the event publisher (class A) is collected.

Here's why:
A delegate has a member called Target. Target is a reference to the
subscriber (Class C). When you add the event, the publisher holds a
reference to the delegate which in turn holds a reference to the
subscriber,
so C is held in memory. The graph looks like this:

A ---> EventDelegate ---->C

So, the reason that you are getting multiple event fires is that you have more instances of C in memory than you think that you do.

What you probably want to do is to keep track of all of the event
subscriptions that C makes and have C implement IDispose. When you are
ready to kill C, call its Dispose method. Inside the Dispose, unsubscribe from all of the events that you are subscribed to.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:uV*************@TK2MSFTNGP09.phx.gbl...
I have a class (let's call it ClassA) that I've written which has events. In another class (let's call it ClassB) I create a collection of ClassA
objects. In a third class (ClassC) I create a reference to some of the
ClassA objects created in ClassB. In ClassC I hook into the ClassA
events
with a foreach loop so that I hook each object. The code is something

like
this:
class ClassC {
void SomeMethod()
{
foreach (ClassA item in ClassACollection)
{
item.MyEvent += new EventHandler(item_MyEvent);
}
}
}

Objects of type ClassC keep getting created and deleted, but the objects
of
ClassA that it references stay in memory. Therefore, every time I load

a new instance of ClassC the event gets hooked again. What I'm seeing is

that
I fire the event once but I end up getting it raised in the code that
responds to it (item_MyEvent method) for every time it was added when I

only
want it to get caught once.

How can I be sure that I only add the handler to the event once for each item? Since the code is in ClassC it's not allowed to inspect the
ClassA.MyEvent to see if something's already hooked to it.

I hope this makes sense. Creating a repro case wouldn't make sense here because it's my application logic that's causing the problem.

Thanks.



Nov 16 '05 #6
Interesting. I was just playing around with the Equals function in the
snippet compiler (http://www.sliver.com/dotnet/SnippetCompiler/) , and I
think that I may have spotted a bug -- I don't want to jump to conclusions,
though.

Correct me if I'm wrong, but if you override Equals, you should also
override GetHashCode (you actually get a compiler warning if you don't -- I
know this part is right). Shouldn't the results of GetHashCode be
consistent with Equals -- two items that are "equal" should return the same
hash code, but two items that are not equal should return different hashes?

I was pretty sure that this is how it was supposed to work. Maybe I'm
wrong. What I find is that it is possible to have 2 delegates where
Equals() is false, but the Hashes returned from GetHashCode are the same.

This can happen if you have 2 different delegates pointing to the same
method name in 2 different object instances. In Reflector, it appears the
Equals() takes into account both the target and the method pointer, but
GetHashCode only takes into account the method pointer (which will be the
same for all instances of the same object, as only the fields are copied in
memory).

Below is a short but complete program to demo (.Net framework v 1.1):

using System;
using System.Collections;

public class MyClass
{
public static void Main()
{
EventTarget handler1 = new EventTarget();
EventTarget handler2 = new EventTarget();
System.EventHandler event1 = new System.EventHandler(handler1.Handler);
System.EventHandler event2 = new System.EventHandler(handler2.Handler);

// first test equal -- should be false
WL("Event1.Equals(Event2): {0}", event1.Equals(event2));
// second test -- hashcode
int hash1 = event1.GetHashCode();
int hash2 = event2.GetHashCode();
WL("Event1 Hash: {0}, Event2 Hash: {1} Hash1 == Hash2: {2}", hash1, hash2,
hash1 == hash2);
RL();
}

private static void WL(string text, params object[] args)
{
Console.WriteLine(text, args);
}

private static void RL()
{
Console.ReadLine();
}

private static void Break()
{
System.Diagnostics.Debugger.Break();
}
}

public class EventTarget
{
public void Handler(object sender, System.EventArgs e)
{
}
}

"J.Marsch" <je****@ctcdeveloper.com> wrote in message
news:%2***************@TK2MSFTNGP10.phx.gbl...
To answer that question, we can fire up Reflector
http://www.aisto.com/roeder/dotnet/ and look at the definition of the
Delegate class. In it, we find that the the Equals() method has been
overridden. Two delegates are considered equal if they both target the same object instance and the same method within that object instance.

So:
event1 = new EventHandler(item_MyEvent);
event2 = new EventHandler(item_MyEvent);

?event1.Equals(event2); // true

When you execute this:
item.MyEvent -= new EventHandler(item_MyEvent);

The publisher goes looking for a delegate that it is holding that is equal
to the one that you passed, and it finds the one that you passed in the +=
statement.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:Os**************@TK2MSFTNGP12.phx.gbl...
Thanks. I figured that I needed to unsubscribe in some way but since I
wasn't storing an internal reference to the subscriber. I added the code
like the following and it solved the problem but I don't really understand why:

item.MyEvent -= new EventHandler(item_MyEvent);

This just seems really odd to me. If the += assignment adds a refernece to
a new event handler it seems that handler would be a different object than the one created with the new operator in the -= assignment. I could see
something like this working:
EventHandler eh = new EventHandler (item_MyEvent);
item.MyEvent += eh;
...then later...
item.MyEvent -= eh;
I can see that working because it's the same object, but when I use the

new
keyword twice don't I have two unique references?

- Rhy
"J.Marsch" <je****@ctcdeveloper.com> wrote in message
news:%2***************@TK2MSFTNGP12.phx.gbl...
Are you unsubscribing the event when you remove the instances of Class C from memory?

If you subscribe to an event and do not unsubscribe, the subscriber will be
held in memory until the event publisher (class A) is collected.

Here's why:
A delegate has a member called Target. Target is a reference to the
subscriber (Class C). When you add the event, the publisher holds a
reference to the delegate which in turn holds a reference to the
subscriber,
so C is held in memory. The graph looks like this:

A ---> EventDelegate ---->C

So, the reason that you are getting multiple event fires is that you

have more instances of C in memory than you think that you do.

What you probably want to do is to keep track of all of the event
subscriptions that C makes and have C implement IDispose. When you are ready to kill C, call its Dispose method. Inside the Dispose, unsubscribe from all of the events that you are subscribed to.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:uV*************@TK2MSFTNGP09.phx.gbl...
> I have a class (let's call it ClassA) that I've written which has events.> In another class (let's call it ClassB) I create a collection of ClassA> objects. In a third class (ClassC) I create a reference to some of the> ClassA objects created in ClassB. In ClassC I hook into the ClassA
> events
> with a foreach loop so that I hook each object. The code is something like
> this:
> class ClassC {
> void SomeMethod()
> {
> foreach (ClassA item in ClassACollection)
> {
> item.MyEvent += new EventHandler(item_MyEvent);
> }
> }
> }
>
> Objects of type ClassC keep getting created and deleted, but the objects of
> ClassA that it references stay in memory. Therefore, every time I load a
> new instance of ClassC the event gets hooked again. What I'm seeing
is that
> I fire the event once but I end up getting it raised in the code that
> responds to it (item_MyEvent method) for every time it was added when I only
> want it to get caught once.
>
> How can I be sure that I only add the handler to the event once for

each> item? Since the code is in ClassC it's not allowed to inspect the
> ClassA.MyEvent to see if something's already hooked to it.
>
> I hope this makes sense. Creating a repro case wouldn't make sense here> because it's my application logic that's causing the problem.
>
> Thanks.
>
>



Nov 16 '05 #7
J.Marsch <je****@ctcdeveloper.com> wrote:
Interesting. I was just playing around with the Equals function in the
snippet compiler (http://www.sliver.com/dotnet/SnippetCompiler/) , and I
think that I may have spotted a bug -- I don't want to jump to conclusions,
though.

Correct me if I'm wrong, but if you override Equals, you should also
override GetHashCode (you actually get a compiler warning if you don't -- I
know this part is right). Shouldn't the results of GetHashCode be
consistent with Equals -- two items that are "equal" should return the same
hash code, but two items that are not equal should return different hashes?


No - two items which are equal should return the same hash code, but
two items which are not equal *may* return the same hash code.
Otherwise you couldn't *possibly* have a hash code for every string,
for instance.

Hash tables perform *better* if unequal objects return unequal hash
codes, but it's not necessary.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #8
Well that clears it up. I'd much rather be wrong than have a bug.

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
J.Marsch <je****@ctcdeveloper.com> wrote:
Interesting. I was just playing around with the Equals function in the
snippet compiler (http://www.sliver.com/dotnet/SnippetCompiler/) , and I
think that I may have spotted a bug -- I don't want to jump to conclusions, though.

Correct me if I'm wrong, but if you override Equals, you should also
override GetHashCode (you actually get a compiler warning if you don't -- I know this part is right). Shouldn't the results of GetHashCode be
consistent with Equals -- two items that are "equal" should return the same hash code, but two items that are not equal should return different
hashes?
No - two items which are equal should return the same hash code, but
two items which are not equal *may* return the same hash code.
Otherwise you couldn't *possibly* have a hash code for every string,
for instance.

Hash tables perform *better* if unequal objects return unequal hash
codes, but it's not necessary.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #9
No no no no no no, this is no reason to implement the IDisposable
interface!

When you implement the IDisposable interface, the design pattern
requires you to implement Finalize as well. The code inside Finalize
calls the Dispose method (it is in other words your failsafe in case
the client does not call Dispose). If you call Dispose manually,
GC.SuppressFinalization is called and the object is not placed in the
Finalization queue.

Now, not only do you not want to get into all this for every class
that subscribes to events, but implementing the Finalize method means
that every instance of that class is placed in the finalization list
of the GC so that it knows not to free up the memory that the object
is occupying before calling its Finalize method. Even if you do call
Dipose manually and you suppress the object's finalization, the
initial cost of placing the object in the finalization list is still
there.

The IDisposable interface should only be implemented when you are
dealing with unmanged resources, which if not freed would cause a
memory leak.

Regards,
Angelos Petropoulos

On Tue, 15 Jun 2004 18:21:05 -0500, "J.Marsch"
<je****@ctcdeveloper.com> wrote:
Are you unsubscribing the event when you remove the instances of Class C
from memory?

If you subscribe to an event and do not unsubscribe, the subscriber will be
held in memory until the event publisher (class A) is collected.

Here's why:
A delegate has a member called Target. Target is a reference to the
subscriber (Class C). When you add the event, the publisher holds a
reference to the delegate which in turn holds a reference to the subscriber,
so C is held in memory. The graph looks like this:

A ---> EventDelegate ---->C

So, the reason that you are getting multiple event fires is that you have
more instances of C in memory than you think that you do.

What you probably want to do is to keep track of all of the event
subscriptions that C makes and have C implement IDispose. When you are
ready to kill C, call its Dispose method. Inside the Dispose, unsubscribe
from all of the events that you are subscribed to.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:uV*************@TK2MSFTNGP09.phx.gbl...
I have a class (let's call it ClassA) that I've written which has events.
In another class (let's call it ClassB) I create a collection of ClassA
objects. In a third class (ClassC) I create a reference to some of the
ClassA objects created in ClassB. In ClassC I hook into the ClassA events
with a foreach loop so that I hook each object. The code is something

like
this:
class ClassC {
void SomeMethod()
{
foreach (ClassA item in ClassACollection)
{
item.MyEvent += new EventHandler(item_MyEvent);
}
}
}

Objects of type ClassC keep getting created and deleted, but the objects

of
ClassA that it references stay in memory. Therefore, every time I load a
new instance of ClassC the event gets hooked again. What I'm seeing is

that
I fire the event once but I end up getting it raised in the code that
responds to it (item_MyEvent method) for every time it was added when I

only
want it to get caught once.

How can I be sure that I only add the handler to the event once for each
item? Since the code is in ClassC it's not allowed to inspect the
ClassA.MyEvent to see if something's already hooked to it.

I hope this makes sense. Creating a repro case wouldn't make sense here
because it's my application logic that's causing the problem.

Thanks.


Nov 16 '05 #10
Angelos Petropoulos <Sp*****@This.Address.Not> wrote:
No no no no no no, this is no reason to implement the IDisposable
interface!

When you implement the IDisposable interface, the design pattern
requires you to implement Finalize as well.


Which design pattern? Although it's *common*, you certainly don't
*have* to implement Finalize as well. If your class wraps another class
which implements IDisposable, but your class doesn't contain any
unmanaged resources *directly*, it makes sense to implement IDispose in
order to dispose of the internal object - but it doesn't make sense to
have a finalizer, as if the internal object is implemented properly,
*it* will have a finalizer which will be called anyway.

There are various examples of this in the normal class library, and
Richter mentions it in Applied Microsoft .NET Framework development.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #11
No no no no no no, this is no reason to implement the IDisposable
interface!

When you implement the IDisposable interface, the design pattern
requires you to implement Finalize as well. The code inside Finalize
calls the Dispose method (it is in other words your failsafe in case
the client does not call Dispose). If you call Dispose manually,
GC.SuppressFinalization is called and the object is not placed in the
Finalization queue.

Now, not only do you not want to get into all this for every class
that subscribes to events, but implementing the Finalize method means
that every instance of that class is placed in the finalization list
of the GC so that it knows not to free up the memory that the object
is occupying before calling its Finalize method. Even if you do call
Dipose manually and you suppress the object's finalization, the
initial cost of placing the object in the finalization list is still
there.

The IDisposable interface should only be implemented when you are
dealing with unmanged resources, which if not freed would cause a
memory leak.

Regards,
Angelos Petropoulos

On Tue, 15 Jun 2004 18:21:05 -0500, "J.Marsch"
<je****@ctcdeveloper.com> wrote:
Are you unsubscribing the event when you remove the instances of Class C
from memory?

If you subscribe to an event and do not unsubscribe, the subscriber will be
held in memory until the event publisher (class A) is collected.

Here's why:
A delegate has a member called Target. Target is a reference to the
subscriber (Class C). When you add the event, the publisher holds a
reference to the delegate which in turn holds a reference to the subscriber,
so C is held in memory. The graph looks like this:

A ---> EventDelegate ---->C

So, the reason that you are getting multiple event fires is that you have
more instances of C in memory than you think that you do.

What you probably want to do is to keep track of all of the event
subscriptions that C makes and have C implement IDispose. When you are
ready to kill C, call its Dispose method. Inside the Dispose, unsubscribe
from all of the events that you are subscribed to.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:uV*************@TK2MSFTNGP09.phx.gbl...
I have a class (let's call it ClassA) that I've written which has events.
In another class (let's call it ClassB) I create a collection of ClassA
objects. In a third class (ClassC) I create a reference to some of the
ClassA objects created in ClassB. In ClassC I hook into the ClassA events
with a foreach loop so that I hook each object. The code is something

like
this:
class ClassC {
void SomeMethod()
{
foreach (ClassA item in ClassACollection)
{
item.MyEvent += new EventHandler(item_MyEvent);
}
}
}

Objects of type ClassC keep getting created and deleted, but the objects

of
ClassA that it references stay in memory. Therefore, every time I load a
new instance of ClassC the event gets hooked again. What I'm seeing is

that
I fire the event once but I end up getting it raised in the code that
responds to it (item_MyEvent method) for every time it was added when I

only
want it to get caught once.

How can I be sure that I only add the handler to the event once for each
item? Since the code is in ClassC it's not allowed to inspect the
ClassA.MyEvent to see if something's already hooked to it.

I hope this makes sense. Creating a repro case wouldn't make sense here
because it's my application logic that's causing the problem.

Thanks.


Nov 16 '05 #12
You are right, in the scenario you describe it wouldn't be necessary
to have a finalizer. I hadn't thought of that, thank you for pointing
it out.

Regards,
Angelos Petropoulos

On Thu, 17 Jun 2004 10:36:50 +0100, Jon Skeet [C# MVP]
<sk***@pobox.com> wrote:
Angelos Petropoulos <Sp*****@This.Address.Not> wrote:
No no no no no no, this is no reason to implement the IDisposable
interface!

When you implement the IDisposable interface, the design pattern
requires you to implement Finalize as well.


Which design pattern? Although it's *common*, you certainly don't
*have* to implement Finalize as well. If your class wraps another class
which implements IDisposable, but your class doesn't contain any
unmanaged resources *directly*, it makes sense to implement IDispose in
order to dispose of the internal object - but it doesn't make sense to
have a finalizer, as if the internal object is implemented properly,
*it* will have a finalizer which will be called anyway.

There are various examples of this in the normal class library, and
Richter mentions it in Applied Microsoft .NET Framework development.


Nov 16 '05 #13
Angelos Petropoulos <Sp*****@This.Address.Not> wrote:
No no no no no no, this is no reason to implement the IDisposable
interface!

When you implement the IDisposable interface, the design pattern
requires you to implement Finalize as well.


Which design pattern? Although it's *common*, you certainly don't
*have* to implement Finalize as well. If your class wraps another class
which implements IDisposable, but your class doesn't contain any
unmanaged resources *directly*, it makes sense to implement IDispose in
order to dispose of the internal object - but it doesn't make sense to
have a finalizer, as if the internal object is implemented properly,
*it* will have a finalizer which will be called anyway.

There are various examples of this in the normal class library, and
Richter mentions it in Applied Microsoft .NET Framework development.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #14
You are right, in the scenario you describe it wouldn't be necessary
to have a finalizer. I hadn't thought of that, thank you for pointing
it out.

Regards,
Angelos Petropoulos

On Thu, 17 Jun 2004 10:36:50 +0100, Jon Skeet [C# MVP]
<sk***@pobox.com> wrote:
Angelos Petropoulos <Sp*****@This.Address.Not> wrote:
No no no no no no, this is no reason to implement the IDisposable
interface!

When you implement the IDisposable interface, the design pattern
requires you to implement Finalize as well.


Which design pattern? Although it's *common*, you certainly don't
*have* to implement Finalize as well. If your class wraps another class
which implements IDisposable, but your class doesn't contain any
unmanaged resources *directly*, it makes sense to implement IDispose in
order to dispose of the internal object - but it doesn't make sense to
have a finalizer, as if the internal object is implemented properly,
*it* will have a finalizer which will be called anyway.

There are various examples of this in the normal class library, and
Richter mentions it in Applied Microsoft .NET Framework development.


Nov 16 '05 #15
The pattern does not require that you implement Finalize and IDisposeable in
tandem. It merely advises that you do so. In this case, implementing a
finalize is unneccessary, and not even fruitful. You generally implement a
finalizer if your object holds unmanaged resources that must be
deterministically released when your managed object goes away. You
complement that finalizer with a Dispose so that the developer can call
dispose and bypass an expensive finalization. Here, we have a completely
different situation.

In the case in this thread, a finalizer would never be called, because if
you don't deterministically dispose this object (and unsubscribe the events)
it is _never eligible_ for collection (or finalization). Well, to be more
accurate: finalize would be called, but only when the event publisher is
elligible for collection. By that time, 1. The subscriber has lived too
long, and 2. there's no use in unsubscribing the events because the event
publisher is already gone.

Rather, by calling Dispose, you are allowing the object to become eligible
for collection. Again, if the object doesn't release its event
subscriptions, it will not even be eligible for collection until the event
publisher is eligible.

You could name the method something else (ReleaseEvents, or whatever), but
it's still fulfilling the same purpose as a Dispose. By naming it Dispose()
and implementing IDisposeable, you do two things:

1. You draw attention to other developers that this is a Disposeable object
( a known pattern), and so (hopefully) increase the likely hood that other
developers will call Dispose on the object
2. By implementing IDisposeable, you make the object compatible with the
Using() statement for automatic disposal when you are finished with it.
"Angelos Petropoulos" <Sp*****@This.Address.Not> wrote in message
news:iu********************************@4ax.com...
No no no no no no, this is no reason to implement the IDisposable
interface!

When you implement the IDisposable interface, the design pattern
requires you to implement Finalize as well. The code inside Finalize
calls the Dispose method (it is in other words your failsafe in case
the client does not call Dispose). If you call Dispose manually,
GC.SuppressFinalization is called and the object is not placed in the
Finalization queue.

Now, not only do you not want to get into all this for every class
that subscribes to events, but implementing the Finalize method means
that every instance of that class is placed in the finalization list
of the GC so that it knows not to free up the memory that the object
is occupying before calling its Finalize method. Even if you do call
Dipose manually and you suppress the object's finalization, the
initial cost of placing the object in the finalization list is still
there.

The IDisposable interface should only be implemented when you are
dealing with unmanged resources, which if not freed would cause a
memory leak.

Regards,
Angelos Petropoulos

On Tue, 15 Jun 2004 18:21:05 -0500, "J.Marsch"
<je****@ctcdeveloper.com> wrote:
Are you unsubscribing the event when you remove the instances of Class C
from memory?

If you subscribe to an event and do not unsubscribe, the subscriber will beheld in memory until the event publisher (class A) is collected.

Here's why:
A delegate has a member called Target. Target is a reference to the
subscriber (Class C). When you add the event, the publisher holds a
reference to the delegate which in turn holds a reference to the subscriber,so C is held in memory. The graph looks like this:

A ---> EventDelegate ---->C

So, the reason that you are getting multiple event fires is that you have
more instances of C in memory than you think that you do.

What you probably want to do is to keep track of all of the event
subscriptions that C makes and have C implement IDispose. When you are
ready to kill C, call its Dispose method. Inside the Dispose, unsubscribefrom all of the events that you are subscribed to.

"Rhy Mednick" <rh*@rhy.com> wrote in message
news:uV*************@TK2MSFTNGP09.phx.gbl...
I have a class (let's call it ClassA) that I've written which has events. In another class (let's call it ClassB) I create a collection of ClassA
objects. In a third class (ClassC) I create a reference to some of the
ClassA objects created in ClassB. In ClassC I hook into the ClassA events with a foreach loop so that I hook each object. The code is something

like
this:
class ClassC {
void SomeMethod()
{
foreach (ClassA item in ClassACollection)
{
item.MyEvent += new EventHandler(item_MyEvent);
}
}
}

Objects of type ClassC keep getting created and deleted, but the objects
of
ClassA that it references stay in memory. Therefore, every time I load

a new instance of ClassC the event gets hooked again. What I'm seeing is

that
I fire the event once but I end up getting it raised in the code that
responds to it (item_MyEvent method) for every time it was added when I

only
want it to get caught once.

How can I be sure that I only add the handler to the event once for each item? Since the code is in ClassC it's not allowed to inspect the
ClassA.MyEvent to see if something's already hooked to it.

I hope this makes sense. Creating a repro case wouldn't make sense here because it's my application logic that's causing the problem.

Thanks.

Nov 16 '05 #16

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Marty McDonald | last post by:
It is still unclear to me why we would use events when delegates seem to do just fine. People say that events make it so the publisher doesn't need to know about the listeners. What does that...
8
by: STom | last post by:
I have a C# Winforms app that has 5 Winforms, lets say A through E. A: Data entry. When data is entered here in any field, values are updated on forms C, D, E.(Not B) B: Data entry form. When...
3
by: Sam | last post by:
I’m just starting to learn delegates. I’m at the very beginning. If I understand correctly, delegates are for when you want to pass a function as a parameter. For example the client provides a...
4
by: LP | last post by:
Hello! I am still transitioning from VB.NET to C#. I undertand the basic concepts of Delegates, more so of Events and somewhat understand AsyncCallback methods. But I need some clarification on...
4
by: Tim | last post by:
There are a set of clients who need to be notified of certain events. I have used events and delegates (publisher-Subscriber model) for the notification mechanism. All the clients register with...
30
by: Burkhard | last post by:
Hi, I am new to C# (with long year experience in C++) and I am a bit confused by the language construct of events. What is it I can do with events that I cannot do with delegates? At the moment...
2
by: kristian.freed | last post by:
Hi, I currently work in a project written fully in C# where we make extensive use of delegates and events. We have a model where a "state", an object holding data but not much code but which...
5
by: raylopez99 | last post by:
I understand delegates (static and non-static) and I agree they are very useful, and that the "Forms" used in the Windows .NET API could not work without them. That said, I'm curious as to how...
7
by: Siegfried Heintze | last post by:
I'm studying the book "Microsoft Visual Basic.NET Language Reference" and I would like some clarify the difference between events and delegates. On page 156 I see a WinForms example of timer that...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.