PC Review


Reply
Thread Tools Rate Thread

Delegate Invocation List contains COPIES of objects, NOT reference

 
 
=?Utf-8?B?Tjg=?=
Guest
Posts: n/a
 
      6th Jan 2005
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.theCallBack);
d1.myStringEvent += new
classContainingDelegate.takesOneString(o2.theCallBack);

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.
 
Reply With Quote
 
 
 
 
Nicholas Paldino [.NET/C# MVP]
Guest
Posts: n/a
 
      6th Jan 2005
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]
- (E-Mail Removed)

"N8" <(E-Mail Removed)> wrote in message
news:C9B44D74-B947-45B8-9938-(E-Mail Removed)...
>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.theCallBack);
> d1.myStringEvent += new
> classContainingDelegate.takesOneString(o2.theCallBack);
>
> 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.



 
Reply With Quote
 
=?Utf-8?B?Tjg=?=
Guest
Posts: n/a
 
      6th Jan 2005
Thanks Nicholas,

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

Thanks again.
 
Reply With Quote
 
Richard Grimes [MVP]
Guest
Posts: n/a
 
      7th Jan 2005
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 (E-Mail Removed) is encrypted with ROT13 (www.rot13.org)


 
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
How to remove a given delegate from the delegate invocation list mehdi Microsoft C# .NET 2 18th Feb 2007 11:02 PM
Force a WinForms User Control to unload, removing its delegate event handler from the invocation list of another class ewolfman Microsoft Dot NET Framework Forms 1 22nd Sep 2006 04:07 PM
asynchronous invocation of a delegate in VB Dave Hall Microsoft Dot NET Framework 0 10th Mar 2005 02:06 AM
How to catch an asynchronous delegate invocation exception? =?Utf-8?B?U2hhcm9u?= Microsoft C# .NET 6 17th Nov 2004 03:17 PM
How to remove delegate from Invocation List? (remote eventing) Lex Microsoft C# .NET 1 30th Apr 2004 11:46 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 01:06 AM.