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

Observation on object references

P: n/a
Observed a weird behaviour with object references.
See code listing below:

using System;
using System.Collections.Generic;
using System.Text;

namespace PointerExceptionTest
{
/*
Desc: Apparent weird behaviour of encapsulated reference types
getting "lost" upon instance renewal.

The following code example shows a basic implementation of the Chain
of Responsibility design
pattern, where the main class (Orchestrator) creates 2 instances of
the Handler classes, (h1
and h2) and chains them together. It then passes an event argument
variable to h1 by calling
its Process method. The args variable contains a data object that
will be inspected after the
chain is complete. It also contains a data variable that is passed as
a reference to the args constructor.

Handler1 simply changes a value if args.data.field1
Handler2 recreates a new instance of data and assigns it to args.data.

We would expect Orchestration.args.data to be updated to the new
reference of data2 in Handler2 and that DOES happen.
We would also expect Orchestration.data to be updated to the new
reference of data2 in Handler2, but that DOES NOT happen!
When the args.data gets assigned to a new data variable,
Orchestration.data loses reference to the new value from then on.
Being a pointer, one would expect it to be updated, but as the output
clearly shows, it does not.

*/
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator();
o.Start();

Console.ReadLine();
}
}

public class Orchestrator
{
IData data = new Data();
IHandlerArgs args = null;

HandlerBase h1 = new Handler1();
HandlerBase h2 = new Handler2();

public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}

}

/* Base class for Handlers */
public abstract class HandlerBase
{
public abstract void Process(IHandlerArgs args);
public HandlerBase successor = null;

}

/* Concrete instance of a handler */
public class Handler1 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data.field1 = "Handerl";
if (successor != null)
{
successor.Process(args);
}
}
}

/* Concrete instance of a handler */
public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

args.data.field1 = "Hander2";
if (successor != null)
{
successor.Process(args);
}
}
}
/* Interface for the argument that is passed to the handler */
public interface IHandlerArgs
{
IData data
{
get;
set;
}
}

/* Concrete instance of HandlerArgs */
public class HandlerArgs : IHandlerArgs
{
public HandlerArgs(IData data)
{
_data = data;
}

IData _data = null;
public IData data
{
get
{
return _data;
}
set
{
_data = value;
}
}

}

/* Interface for the data packet that will be
encapsulated in the HandlerArgs.
*/
public interface IData
{
string field1
{
get;
set;
}
}

/* Concrete instance of a data packet */
public class Data : IData
{
private string _field1 = "null";
public string field1
{
get
{
return _field1;
}
set
{
_field1 = value;
}
}

}

}

--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
Nov 15 '06 #1
Share this Question
Share on Google+
6 Replies


P: n/a
Hi Shailen,
if you run your code you get the following output o the command line:

args.data.field1: Handler2
data.field1: Handler1

To me that seems exactly what I would expect. Basically you Orchestrator
object o initially creates a Data object data (we will call this d1) and
passes in the reference to that to the args variable, at this point we know:
o.args.data.field1 == "null", where data refers to d1 instance.

You then call processs and pass in the args variable, Handler1 changes the
field1 value so:
o.args.data.field1 == "Handler1"

everything is good so far, the args instance is passed to Handler2, at this
point Handler2 creates a new instance of the Data object (call this d2) and
passes that to the args object, so before we had:

o.args.data -referring to d1 instance we created earlier.

now we have o.args.data -refers to d2, and set the field value
o.args.data.field1 == "handler2"

so back in the following code:
public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}

args.data refers to Data instance d2, so args.data.field1 == "handler2" and
your original data field d1 will still have a field value of "Handler1". The
important point to note is when you did:

public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

you replaced what the args instance referenced. What were you expecting to
happen?

Mark.
--
http://www.markdawson.org
"Shailen Sukul" wrote:
Observed a weird behaviour with object references.
See code listing below:

using System;
using System.Collections.Generic;
using System.Text;

namespace PointerExceptionTest
{
/*
Desc: Apparent weird behaviour of encapsulated reference types
getting "lost" upon instance renewal.

The following code example shows a basic implementation of the Chain
of Responsibility design
pattern, where the main class (Orchestrator) creates 2 instances of
the Handler classes, (h1
and h2) and chains them together. It then passes an event argument
variable to h1 by calling
its Process method. The args variable contains a data object that
will be inspected after the
chain is complete. It also contains a data variable that is passed as
a reference to the args constructor.

Handler1 simply changes a value if args.data.field1
Handler2 recreates a new instance of data and assigns it to args.data.

We would expect Orchestration.args.data to be updated to the new
reference of data2 in Handler2 and that DOES happen.
We would also expect Orchestration.data to be updated to the new
reference of data2 in Handler2, but that DOES NOT happen!
When the args.data gets assigned to a new data variable,
Orchestration.data loses reference to the new value from then on.
Being a pointer, one would expect it to be updated, but as the output
clearly shows, it does not.

*/
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator();
o.Start();

Console.ReadLine();
}
}

public class Orchestrator
{
IData data = new Data();
IHandlerArgs args = null;

HandlerBase h1 = new Handler1();
HandlerBase h2 = new Handler2();

public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}

}

/* Base class for Handlers */
public abstract class HandlerBase
{
public abstract void Process(IHandlerArgs args);
public HandlerBase successor = null;

}

/* Concrete instance of a handler */
public class Handler1 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data.field1 = "Handerl";
if (successor != null)
{
successor.Process(args);
}
}
}

/* Concrete instance of a handler */
public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

args.data.field1 = "Hander2";
if (successor != null)
{
successor.Process(args);
}
}
}
/* Interface for the argument that is passed to the handler */
public interface IHandlerArgs
{
IData data
{
get;
set;
}
}

/* Concrete instance of HandlerArgs */
public class HandlerArgs : IHandlerArgs
{
public HandlerArgs(IData data)
{
_data = data;
}

IData _data = null;
public IData data
{
get
{
return _data;
}
set
{
_data = value;
}
}

}

/* Interface for the data packet that will be
encapsulated in the HandlerArgs.
*/
public interface IData
{
string field1
{
get;
set;
}
}

/* Concrete instance of a data packet */
public class Data : IData
{
private string _field1 = "null";
public string field1
{
get
{
return _field1;
}
set
{
_field1 = value;
}
}

}

}

--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
Nov 15 '06 #2

P: n/a
Hi Shailen,

The local "data" variable was never changed to point to the new reference.

The behavior you are witnessing may be condensed into a simple example. This
is what's happening in your code, minus all the bloat:

IData data = new Data();
IHandlerArgs args = new HandlerArgs(data);

args.data.field1 = "Handler 1";

// Note: this assignment doesn't update the local "data" variable
// to the new reference. After, you'll have references to two instances
args.data = new Data();

args.data.field1 = "Handler 2";

Console.WriteLine("Encapsulated value: " + args.data.field1);
// Prints "Handler 2"

Console.WriteLine("Local value: " + data.field1);
// Prints "Handler 1" because args.data reference was still the same
// as the local "data" variable

--
Dave Sexton

"Shailen Sukul" <sh***@ashlen.net.auwrote in message
news:14**********************************@microsof t.com...
Observed a weird behaviour with object references.
See code listing below:

using System;
using System.Collections.Generic;
using System.Text;

namespace PointerExceptionTest
{
/*
Desc: Apparent weird behaviour of encapsulated reference types
getting "lost" upon instance renewal.

The following code example shows a basic implementation of the Chain
of Responsibility design
pattern, where the main class (Orchestrator) creates 2 instances of
the Handler classes, (h1
and h2) and chains them together. It then passes an event argument
variable to h1 by calling
its Process method. The args variable contains a data object that
will be inspected after the
chain is complete. It also contains a data variable that is passed as
a reference to the args constructor.

Handler1 simply changes a value if args.data.field1
Handler2 recreates a new instance of data and assigns it to args.data.

We would expect Orchestration.args.data to be updated to the new
reference of data2 in Handler2 and that DOES happen.
We would also expect Orchestration.data to be updated to the new
reference of data2 in Handler2, but that DOES NOT happen!
When the args.data gets assigned to a new data variable,
Orchestration.data loses reference to the new value from then on.
Being a pointer, one would expect it to be updated, but as the output
clearly shows, it does not.

*/
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator();
o.Start();

Console.ReadLine();
}
}

public class Orchestrator
{
IData data = new Data();
IHandlerArgs args = null;

HandlerBase h1 = new Handler1();
HandlerBase h2 = new Handler2();

public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}",
data.field1));
}

}

/* Base class for Handlers */
public abstract class HandlerBase
{
public abstract void Process(IHandlerArgs args);
public HandlerBase successor = null;

}

/* Concrete instance of a handler */
public class Handler1 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data.field1 = "Handerl";
if (successor != null)
{
successor.Process(args);
}
}
}

/* Concrete instance of a handler */
public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

args.data.field1 = "Hander2";
if (successor != null)
{
successor.Process(args);
}
}
}
/* Interface for the argument that is passed to the handler */
public interface IHandlerArgs
{
IData data
{
get;
set;
}
}

/* Concrete instance of HandlerArgs */
public class HandlerArgs : IHandlerArgs
{
public HandlerArgs(IData data)
{
_data = data;
}

IData _data = null;
public IData data
{
get
{
return _data;
}
set
{
_data = value;
}
}

}

/* Interface for the data packet that will be
encapsulated in the HandlerArgs.
*/
public interface IData
{
string field1
{
get;
set;
}
}

/* Concrete instance of a data packet */
public class Data : IData
{
private string _field1 = "null";
public string field1
{
get
{
return _field1;
}
set
{
_field1 = value;
}
}

}

}

--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)

Nov 15 '06 #3

P: n/a
yes you are right.
I was *hoping* that the data variable would get updated to "Handler2" but
what I forgot that o.args.data is a referemce type and re-assigning it does
not guarantee that whatever is pointing to it will get updated. o.args.data
just gets re-pointed to a new memory location and data is still pointing at
the old memory location.

Wouldn't it be nice if we could declare a reference type in C# that would
get updated along with its referenced variable.
so data --args.data
args.data gets a new reference
data --new reference

(sigh)
--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
"Mark R. Dawson" wrote:
Hi Shailen,
if you run your code you get the following output o the command line:

args.data.field1: Handler2
data.field1: Handler1

To me that seems exactly what I would expect. Basically you Orchestrator
object o initially creates a Data object data (we will call this d1) and
passes in the reference to that to the args variable, at this point we know:
o.args.data.field1 == "null", where data refers to d1 instance.

You then call processs and pass in the args variable, Handler1 changes the
field1 value so:
o.args.data.field1 == "Handler1"

everything is good so far, the args instance is passed to Handler2, at this
point Handler2 creates a new instance of the Data object (call this d2) and
passes that to the args object, so before we had:

o.args.data -referring to d1 instance we created earlier.

now we have o.args.data -refers to d2, and set the field value
o.args.data.field1 == "handler2"

so back in the following code:
public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}

args.data refers to Data instance d2, so args.data.field1 == "handler2" and
your original data field d1 will still have a field value of "Handler1". The
important point to note is when you did:

public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

you replaced what the args instance referenced. What were you expecting to
happen?

Mark.
--
http://www.markdawson.org
"Shailen Sukul" wrote:
Observed a weird behaviour with object references.
See code listing below:

using System;
using System.Collections.Generic;
using System.Text;

namespace PointerExceptionTest
{
/*
Desc: Apparent weird behaviour of encapsulated reference types
getting "lost" upon instance renewal.

The following code example shows a basic implementation of the Chain
of Responsibility design
pattern, where the main class (Orchestrator) creates 2 instances of
the Handler classes, (h1
and h2) and chains them together. It then passes an event argument
variable to h1 by calling
its Process method. The args variable contains a data object that
will be inspected after the
chain is complete. It also contains a data variable that is passed as
a reference to the args constructor.

Handler1 simply changes a value if args.data.field1
Handler2 recreates a new instance of data and assigns it to args.data.

We would expect Orchestration.args.data to be updated to the new
reference of data2 in Handler2 and that DOES happen.
We would also expect Orchestration.data to be updated to the new
reference of data2 in Handler2, but that DOES NOT happen!
When the args.data gets assigned to a new data variable,
Orchestration.data loses reference to the new value from then on.
Being a pointer, one would expect it to be updated, but as the output
clearly shows, it does not.

*/
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator();
o.Start();

Console.ReadLine();
}
}

public class Orchestrator
{
IData data = new Data();
IHandlerArgs args = null;

HandlerBase h1 = new Handler1();
HandlerBase h2 = new Handler2();

public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}

}

/* Base class for Handlers */
public abstract class HandlerBase
{
public abstract void Process(IHandlerArgs args);
public HandlerBase successor = null;

}

/* Concrete instance of a handler */
public class Handler1 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data.field1 = "Handerl";
if (successor != null)
{
successor.Process(args);
}
}
}

/* Concrete instance of a handler */
public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

args.data.field1 = "Hander2";
if (successor != null)
{
successor.Process(args);
}
}
}
/* Interface for the argument that is passed to the handler */
public interface IHandlerArgs
{
IData data
{
get;
set;
}
}

/* Concrete instance of HandlerArgs */
public class HandlerArgs : IHandlerArgs
{
public HandlerArgs(IData data)
{
_data = data;
}

IData _data = null;
public IData data
{
get
{
return _data;
}
set
{
_data = value;
}
}

}

/* Interface for the data packet that will be
encapsulated in the HandlerArgs.
*/
public interface IData
{
string field1
{
get;
set;
}
}

/* Concrete instance of a data packet */
public class Data : IData
{
private string _field1 = "null";
public string field1
{
get
{
return _field1;
}
set
{
_field1 = value;
}
}

}

}

--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
Nov 15 '06 #4

P: n/a
I guess if you really want that kind of semantics you can always use pointer
in C# which will give you that ability, however there are definitely more
elegant ways around it.

You could use an event so that when the data in the HandlerArgs is modified
all items that reference that data can update themselves i.e.

using System;
using System.Collections.Generic;
using System.Text;

namespace PointerExceptionTest
{
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator();
o.Start();

Console.ReadLine();
}
}

public class Orchestrator
{
IData data = new Data();
HandlerArgs args = null;

HandlerBase h1 = new Handler1();
HandlerBase h2 = new Handler2();

public void Start()
{
args = new HandlerArgs(data);
args.DataChanged += new
HandlerArgs.DataChangedEventHandler(args_DataChang ed);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}

void args_DataChanged(IData data)
{
this.data = data;
}

}

/* Base class for Handlers */
public abstract class HandlerBase
{
public abstract void Process(HandlerArgs args);
public HandlerBase successor = null;

}

/* Concrete instance of a handler */
public class Handler1 : HandlerBase
{
public override void Process(HandlerArgs args)
{
args.data.field1 = "Handerl";
if (successor != null)
{
successor.Process(args);
}
}
}

/* Concrete instance of a handler */
public class Handler2 : HandlerBase
{
public override void Process(HandlerArgs args)
{
args.data = new Data();

args.data.field1 = "Hander2";
if (successor != null)
{
successor.Process(args);
}
}
}

/* Concrete instance of HandlerArgs */
public class HandlerArgs
{
public HandlerArgs(IData data)
{
_data = data;
}

IData _data = null;
public IData data
{
get
{
return _data;
}
set
{
_data = value;

//Let everyone know the data has changed.
if (DataChanged != null)
{
DataChanged(_data);
}
}
}

public delegate void DataChangedEventHandler(IData data);
public event DataChangedEventHandler DataChanged;
}

/* Interface for the data packet that will be
encapsulated in the HandlerArgs.
*/
public interface IData
{
string field1
{
get;
set;
}
}

/* Concrete instance of a data packet */
public class Data : IData
{
private string _field1 = "null";
public string field1
{
get
{
return _field1;
}
set
{
_field1 = value;
}
}

}

}
Mark.
--
http://www.markdawson.org
"Shailen Sukul" wrote:
yes you are right.
I was *hoping* that the data variable would get updated to "Handler2" but
what I forgot that o.args.data is a referemce type and re-assigning it does
not guarantee that whatever is pointing to it will get updated. o.args.data
just gets re-pointed to a new memory location and data is still pointing at
the old memory location.

Wouldn't it be nice if we could declare a reference type in C# that would
get updated along with its referenced variable.
so data --args.data
args.data gets a new reference
data --new reference

(sigh)
--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
"Mark R. Dawson" wrote:
Hi Shailen,
if you run your code you get the following output o the command line:

args.data.field1: Handler2
data.field1: Handler1

To me that seems exactly what I would expect. Basically you Orchestrator
object o initially creates a Data object data (we will call this d1) and
passes in the reference to that to the args variable, at this point we know:
o.args.data.field1 == "null", where data refers to d1 instance.

You then call processs and pass in the args variable, Handler1 changes the
field1 value so:
o.args.data.field1 == "Handler1"

everything is good so far, the args instance is passed to Handler2, at this
point Handler2 creates a new instance of the Data object (call this d2) and
passes that to the args object, so before we had:

o.args.data -referring to d1 instance we created earlier.

now we have o.args.data -refers to d2, and set the field value
o.args.data.field1 == "handler2"

so back in the following code:
public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}

args.data refers to Data instance d2, so args.data.field1 == "handler2" and
your original data field d1 will still have a field value of "Handler1". The
important point to note is when you did:

public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

you replaced what the args instance referenced. What were you expecting to
happen?

Mark.
--
http://www.markdawson.org
"Shailen Sukul" wrote:
Observed a weird behaviour with object references.
See code listing below:
>
using System;
using System.Collections.Generic;
using System.Text;
>
namespace PointerExceptionTest
{
/*
Desc: Apparent weird behaviour of encapsulated reference types
getting "lost" upon instance renewal.
>
The following code example shows a basic implementation of the Chain
of Responsibility design
pattern, where the main class (Orchestrator) creates 2 instances of
the Handler classes, (h1
and h2) and chains them together. It then passes an event argument
variable to h1 by calling
its Process method. The args variable contains a data object that
will be inspected after the
chain is complete. It also contains a data variable that is passed as
a reference to the args constructor.
>
Handler1 simply changes a value if args.data.field1
Handler2 recreates a new instance of data and assigns it to args.data.
>
We would expect Orchestration.args.data to be updated to the new
reference of data2 in Handler2 and that DOES happen.
We would also expect Orchestration.data to be updated to the new
reference of data2 in Handler2, but that DOES NOT happen!
When the args.data gets assigned to a new data variable,
Orchestration.data loses reference to the new value from then on.
Being a pointer, one would expect it to be updated, but as the output
clearly shows, it does not.
>
*/
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator();
o.Start();
>
Console.ReadLine();
}
}
>
public class Orchestrator
{
IData data = new Data();
IHandlerArgs args = null;
>
HandlerBase h1 = new Handler1();
HandlerBase h2 = new Handler2();
>
public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);
>
Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}
>
}
>
/* Base class for Handlers */
public abstract class HandlerBase
{
public abstract void Process(IHandlerArgs args);
public HandlerBase successor = null;
>
}
>
/* Concrete instance of a handler */
public class Handler1 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data.field1 = "Handerl";
if (successor != null)
{
successor.Process(args);
}
}
}
>
/* Concrete instance of a handler */
public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();
>
args.data.field1 = "Hander2";
if (successor != null)
{
successor.Process(args);
}
}
}
>
>
/* Interface for the argument that is passed to the handler */
public interface IHandlerArgs
{
IData data
{
get;
set;
}
}
>
/* Concrete instance of HandlerArgs */
public class HandlerArgs : IHandlerArgs
{
public HandlerArgs(IData data)
{
_data = data;
}
>
IData _data = null;
public IData data
{
get
{
return _data;
}
set
{
_data = value;
}
}
>
}
>
/* Interface for the data packet that will be
encapsulated in the HandlerArgs.
*/
public interface IData
{
string field1
{
get;
set;
}
}
>
/* Concrete instance of a data packet */
public class Data : IData
{
private string _field1 = "null";
public string field1
{
get
{
return _field1;
}
set
{
_field1 = value;
}
}
>
}
>
}
>
--
Good luck!
>
Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
Nov 15 '06 #5

P: n/a
What you want to do it pass a reference value to a function and if the
function updates it with a new reference, have it update the caller?
Simply mark the parameter with the ref keyword in c# which passes a
reference to the reference to the object so it can be updated. All uses of
the parameter in the function are exactly the same.

Ciaran O'Donnell

"Shailen Sukul" wrote:
yes you are right.
I was *hoping* that the data variable would get updated to "Handler2" but
what I forgot that o.args.data is a referemce type and re-assigning it does
not guarantee that whatever is pointing to it will get updated. o.args.data
just gets re-pointed to a new memory location and data is still pointing at
the old memory location.

Wouldn't it be nice if we could declare a reference type in C# that would
get updated along with its referenced variable.
so data --args.data
args.data gets a new reference
data --new reference

(sigh)
--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
"Mark R. Dawson" wrote:
Hi Shailen,
if you run your code you get the following output o the command line:

args.data.field1: Handler2
data.field1: Handler1

To me that seems exactly what I would expect. Basically you Orchestrator
object o initially creates a Data object data (we will call this d1) and
passes in the reference to that to the args variable, at this point we know:
o.args.data.field1 == "null", where data refers to d1 instance.

You then call processs and pass in the args variable, Handler1 changes the
field1 value so:
o.args.data.field1 == "Handler1"

everything is good so far, the args instance is passed to Handler2, at this
point Handler2 creates a new instance of the Data object (call this d2) and
passes that to the args object, so before we had:

o.args.data -referring to d1 instance we created earlier.

now we have o.args.data -refers to d2, and set the field value
o.args.data.field1 == "handler2"

so back in the following code:
public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}

args.data refers to Data instance d2, so args.data.field1 == "handler2" and
your original data field d1 will still have a field value of "Handler1". The
important point to note is when you did:

public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

you replaced what the args instance referenced. What were you expecting to
happen?

Mark.
--
http://www.markdawson.org
"Shailen Sukul" wrote:
Observed a weird behaviour with object references.
See code listing below:
>
using System;
using System.Collections.Generic;
using System.Text;
>
namespace PointerExceptionTest
{
/*
Desc: Apparent weird behaviour of encapsulated reference types
getting "lost" upon instance renewal.
>
The following code example shows a basic implementation of the Chain
of Responsibility design
pattern, where the main class (Orchestrator) creates 2 instances of
the Handler classes, (h1
and h2) and chains them together. It then passes an event argument
variable to h1 by calling
its Process method. The args variable contains a data object that
will be inspected after the
chain is complete. It also contains a data variable that is passed as
a reference to the args constructor.
>
Handler1 simply changes a value if args.data.field1
Handler2 recreates a new instance of data and assigns it to args.data.
>
We would expect Orchestration.args.data to be updated to the new
reference of data2 in Handler2 and that DOES happen.
We would also expect Orchestration.data to be updated to the new
reference of data2 in Handler2, but that DOES NOT happen!
When the args.data gets assigned to a new data variable,
Orchestration.data loses reference to the new value from then on.
Being a pointer, one would expect it to be updated, but as the output
clearly shows, it does not.
>
*/
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator();
o.Start();
>
Console.ReadLine();
}
}
>
public class Orchestrator
{
IData data = new Data();
IHandlerArgs args = null;
>
HandlerBase h1 = new Handler1();
HandlerBase h2 = new Handler2();
>
public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);
>
Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}", data.field1));
}
>
}
>
/* Base class for Handlers */
public abstract class HandlerBase
{
public abstract void Process(IHandlerArgs args);
public HandlerBase successor = null;
>
}
>
/* Concrete instance of a handler */
public class Handler1 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data.field1 = "Handerl";
if (successor != null)
{
successor.Process(args);
}
}
}
>
/* Concrete instance of a handler */
public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();
>
args.data.field1 = "Hander2";
if (successor != null)
{
successor.Process(args);
}
}
}
>
>
/* Interface for the argument that is passed to the handler */
public interface IHandlerArgs
{
IData data
{
get;
set;
}
}
>
/* Concrete instance of HandlerArgs */
public class HandlerArgs : IHandlerArgs
{
public HandlerArgs(IData data)
{
_data = data;
}
>
IData _data = null;
public IData data
{
get
{
return _data;
}
set
{
_data = value;
}
}
>
}
>
/* Interface for the data packet that will be
encapsulated in the HandlerArgs.
*/
public interface IData
{
string field1
{
get;
set;
}
}
>
/* Concrete instance of a data packet */
public class Data : IData
{
private string _field1 = "null";
public string field1
{
get
{
return _field1;
}
set
{
_field1 = value;
}
}
>
}
>
}
>
--
Good luck!
>
Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
Nov 15 '06 #6

P: n/a
Hi Ciaran,

The "ref" keyword doesn't help in this situation.

Assigning a new instance to a "ref" argument doesn't change the old reference
in the original variable, it simply reassigns the reference of the local
variable:

class Program
{
public object obj;

public void SetAndReassignField(ref object refParam)
{
this.obj = refParam;
this.obj = new object();
}

public void SetAndReassignArg(ref object refParam)
{
this.obj = refParam;
refParam = new object();
}

static void Main()
{
Program program = new Program();

object obj = new object();
program.SetAndReassignArg(ref obj);

Console.WriteLine(obj == program.obj);

obj = new object();
program.SetAndReassignField(ref obj);

Console.WriteLine(obj == program.obj);

Console.ReadLine();
}
}

Output:

False
False

Neither reference of the new instances were retained by the local "obj"
parameter in the Main method.

--
Dave Sexton

"Ciaran O''Donnell" <Ci************@discussions.microsoft.comwrote in
message news:86**********************************@microsof t.com...
What you want to do it pass a reference value to a function and if the
function updates it with a new reference, have it update the caller?
Simply mark the parameter with the ref keyword in c# which passes a
reference to the reference to the object so it can be updated. All uses of
the parameter in the function are exactly the same.

Ciaran O'Donnell

"Shailen Sukul" wrote:
>yes you are right.
I was *hoping* that the data variable would get updated to "Handler2" but
what I forgot that o.args.data is a referemce type and re-assigning it does
not guarantee that whatever is pointing to it will get updated. o.args.data
just gets re-pointed to a new memory location and data is still pointing at
the old memory location.

Wouldn't it be nice if we could declare a reference type in C# that would
get updated along with its referenced variable.
so data --args.data
args.data gets a new reference
data --new reference

(sigh)
--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)
"Mark R. Dawson" wrote:
Hi Shailen,
if you run your code you get the following output o the command line:

args.data.field1: Handler2
data.field1: Handler1

To me that seems exactly what I would expect. Basically you Orchestrator
object o initially creates a Data object data (we will call this d1) and
passes in the reference to that to the args variable, at this point we
know:
o.args.data.field1 == "null", where data refers to d1 instance.

You then call processs and pass in the args variable, Handler1 changes
the
field1 value so:
o.args.data.field1 == "Handler1"

everything is good so far, the args instance is passed to Handler2, at
this
point Handler2 creates a new instance of the Data object (call this d2)
and
passes that to the args object, so before we had:

o.args.data -referring to d1 instance we created earlier.

now we have o.args.data -refers to d2, and set the field value
o.args.data.field1 == "handler2"

so back in the following code:
public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}",
data.field1));
}

args.data refers to Data instance d2, so args.data.field1 == "handler2"
and
your original data field d1 will still have a field value of "Handler1".
The
important point to note is when you did:

public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

you replaced what the args instance referenced. What were you expecting
to
happen?

Mark.
--
http://www.markdawson.org
"Shailen Sukul" wrote:

Observed a weird behaviour with object references.
See code listing below:

using System;
using System.Collections.Generic;
using System.Text;

namespace PointerExceptionTest
{
/*
Desc: Apparent weird behaviour of encapsulated reference types
getting "lost" upon instance renewal.

The following code example shows a basic implementation of the
Chain
of Responsibility design
pattern, where the main class (Orchestrator) creates 2 instances
of
the Handler classes, (h1
and h2) and chains them together. It then passes an event
argument
variable to h1 by calling
its Process method. The args variable contains a data object
that
will be inspected after the
chain is complete. It also contains a data variable that is
passed as
a reference to the args constructor.

Handler1 simply changes a value if args.data.field1
Handler2 recreates a new instance of data and assigns it to
args.data.

We would expect Orchestration.args.data to be updated to the new
reference of data2 in Handler2 and that DOES happen.
We would also expect Orchestration.data to be updated to the new
reference of data2 in Handler2, but that DOES NOT happen!
When the args.data gets assigned to a new data variable,
Orchestration.data loses reference to the new value from then on.
Being a pointer, one would expect it to be updated, but as the
output
clearly shows, it does not.

*/
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator();
o.Start();

Console.ReadLine();
}
}

public class Orchestrator
{
IData data = new Data();
IHandlerArgs args = null;

HandlerBase h1 = new Handler1();
HandlerBase h2 = new Handler2();

public void Start()
{
args = new HandlerArgs(data);
h1.successor = h2;
h1.Process(args);

Console.WriteLine(string.Format("args.data.field1:
{0}",args.data.field1));
Console.WriteLine(string.Format("data.field1: {0}",
data.field1));
}

}

/* Base class for Handlers */
public abstract class HandlerBase
{
public abstract void Process(IHandlerArgs args);
public HandlerBase successor = null;

}

/* Concrete instance of a handler */
public class Handler1 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data.field1 = "Handerl";
if (successor != null)
{
successor.Process(args);
}
}
}

/* Concrete instance of a handler */
public class Handler2 : HandlerBase
{
public override void Process(IHandlerArgs args)
{
args.data = new Data();

args.data.field1 = "Hander2";
if (successor != null)
{
successor.Process(args);
}
}
}
/* Interface for the argument that is passed to the handler */
public interface IHandlerArgs
{
IData data
{
get;
set;
}
}

/* Concrete instance of HandlerArgs */
public class HandlerArgs : IHandlerArgs
{
public HandlerArgs(IData data)
{
_data = data;
}

IData _data = null;
public IData data
{
get
{
return _data;
}
set
{
_data = value;
}
}

}

/* Interface for the data packet that will be
encapsulated in the HandlerArgs.
*/
public interface IData
{
string field1
{
get;
set;
}
}

/* Concrete instance of a data packet */
public class Data : IData
{
private string _field1 = "null";
public string field1
{
get
{
return _field1;
}
set
{
_field1 = value;
}
}

}

}

--
Good luck!

Shailen Sukul
Architect
(BSc MCTS, MCSD.Net MCSD MCAD)
Ashlen Consulting Service P/L
(http://www.ashlen.net.au)

Nov 15 '06 #7

This discussion thread is closed

Replies have been disabled for this discussion.