By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,949 Members | 1,511 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,949 IT Pros & Developers. It's quick & easy.

Delegate Invocation List contains COPIES of objects, NOT reference

P: n/a
N8
I am trying to get an exception to occur and consequently found that when
adding a target method to a delegates invocation list, a copy of that object
is added instead of a reference to the object.

Here's what I'm trying to do... I am iterating through the invocation list
invoking each delegate manually. I want to eventually try to invoke a
delegate to an object that has been destroyed. I'm essentially looking to get
the exception "object not set to an instance of an object" or some kind of
exception.

I've created two classes to test with, one class has a delegate as follows:

public class classContainsDelegate{
public delegate void takesOneString(string message);
public takesOneString myStringEvent;

public void raiseEvent(string message){
if(myStringEvent != null){
foreach(takesOneString d in myStringEvent.GetInvocationList()){
d(message);
}//foreach
}//if
}//raiseevent
}//class
I have another class that is going to simply display the message, when
called by the above delegate:

public class classBeingCalledBack(string key){
private string key = "";

public classBeingCalledBack(string theKey){
key = theKey;
}//new method

public string Key{
get{return key;}
}//key property

public void theCallback(string message){
Console.WriteLine("theCallback received '{0}' by '{1}', message, key);
}//the callback
}//class
My test routine starts out like this:

classContainingDelegate d1 = new classContainingDelegate();
classBeingCalledBack o1 = new classBeingCalledBack("first instance");
classBeingCalledBack o2 = new classBeingCalledBack("second instance");

d1.myStringEvent += new
classContainingDelegate.takesOneString(o1.theCallB ack);
d1.myStringEvent += new
classContainingDelegate.takesOneString(o2.theCallB ack);

d1.raiseEvent("message #1");

When I run this test, the 2 callbacks are made to both objects and I see the
messages being displayed that the callbacks happened for objects keyed "first
instance" and "second instance".

Now I want to kill the "first instance" object altogether. I want to cause
an exception when the delegate goes to make a callback to an object that
shouldn't exist anymore. So I then add the following lines to my test routine:

o1 = null;
d1.raiseEvent("message #2");

When doing this, I still get both callbacks still. No exceptions being thrown!

Now, even if I go and change o1 like:
o1 = new classBeingCalledBack("first instance - version 2");

When the delegate is called for "o1", I would expect to see a message that
the callback occurred for "first instance - version 2", but instead I see
"first instance" which should have been overwritten.

I have tried forcing a garbage collection, no difference.

I have tried creating an Event instead of using a delegate (yeah I know its
the same thing, but the rules slightly differ between the two) and no
difference.

Anybody have any ideas? What am I doing wrong or not getting here?

Thanks in advance.
Nov 16 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
N8,

The reason this happens is that when you create a delegate, the delegate
itself holds a reference to the object that the method is on. This way,
when you set the original reference to null, and do a GC, the object still
lives, because you are holding the delegate, which holds the object.

A copy of the object is not made, but rather, the original is just kept
alive because you are holding a reference (indirectly through the delegate)
to it.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"N8" <N8@discussions.microsoft.com> wrote in message
news:C9**********************************@microsof t.com...
I am trying to get an exception to occur and consequently found that when
adding a target method to a delegates invocation list, a copy of that
object
is added instead of a reference to the object.

Here's what I'm trying to do... I am iterating through the invocation list
invoking each delegate manually. I want to eventually try to invoke a
delegate to an object that has been destroyed. I'm essentially looking to
get
the exception "object not set to an instance of an object" or some kind of
exception.

I've created two classes to test with, one class has a delegate as
follows:

public class classContainsDelegate{
public delegate void takesOneString(string message);
public takesOneString myStringEvent;

public void raiseEvent(string message){
if(myStringEvent != null){
foreach(takesOneString d in myStringEvent.GetInvocationList()){
d(message);
}//foreach
}//if
}//raiseevent
}//class
I have another class that is going to simply display the message, when
called by the above delegate:

public class classBeingCalledBack(string key){
private string key = "";

public classBeingCalledBack(string theKey){
key = theKey;
}//new method

public string Key{
get{return key;}
}//key property

public void theCallback(string message){
Console.WriteLine("theCallback received '{0}' by '{1}', message, key);
}//the callback
}//class
My test routine starts out like this:

classContainingDelegate d1 = new classContainingDelegate();
classBeingCalledBack o1 = new classBeingCalledBack("first instance");
classBeingCalledBack o2 = new classBeingCalledBack("second instance");

d1.myStringEvent += new
classContainingDelegate.takesOneString(o1.theCallB ack);
d1.myStringEvent += new
classContainingDelegate.takesOneString(o2.theCallB ack);

d1.raiseEvent("message #1");

When I run this test, the 2 callbacks are made to both objects and I see
the
messages being displayed that the callbacks happened for objects keyed
"first
instance" and "second instance".

Now I want to kill the "first instance" object altogether. I want to cause
an exception when the delegate goes to make a callback to an object that
shouldn't exist anymore. So I then add the following lines to my test
routine:

o1 = null;
d1.raiseEvent("message #2");

When doing this, I still get both callbacks still. No exceptions being
thrown!

Now, even if I go and change o1 like:
o1 = new classBeingCalledBack("first instance - version 2");

When the delegate is called for "o1", I would expect to see a message
that
the callback occurred for "first instance - version 2", but instead I see
"first instance" which should have been overwritten.

I have tried forcing a garbage collection, no difference.

I have tried creating an Event instead of using a delegate (yeah I know
its
the same thing, but the rules slightly differ between the two) and no
difference.

Anybody have any ideas? What am I doing wrong or not getting here?

Thanks in advance.

Nov 16 '05 #2

P: n/a
N8
Thanks Nicholas,

You are right! I completely forgot the rules there when doing this test. (I
blame my xmas vacation - lol).

Thanks again.
Nov 16 '05 #3

P: n/a
Nicholas Paldino [.NET/C# MVP] wrote:
N8,

The reason this happens is that when you create a delegate, the
delegate itself holds a reference to the object that the method is
on. This way, when you set the original reference to null, and do a
GC, the object still lives, because you are holding the delegate,
which holds the object.
A copy of the object is not made, but rather, the original is just
kept alive because you are holding a reference (indirectly through
the delegate) to it.


Indeed, But of course the delegate is serializable, if the objects that are
reference are also serializable. Which gives you the odd situation that you
can serialize a delegate, shutdown the app, re start the app, deserialize
the delegate and invoke it. Resurection of the objects!

Richard
--
www.richardgrimes.com
my email ev******@zicf.bet is encrypted with ROT13 (www.rot13.org)
Nov 16 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.