473,386 Members | 1,706 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.

Observation on object references

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
6 2453
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
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
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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
by: Chris S. | last post by:
I'm trying to make a graphical editor and browser for Pickled files. One aspect I'm not sure about is how to detect multiple references to the same data. For instance, say I had the Pickled...
4
by: Mark D. Anderson | last post by:
About a month ago Richard Cornford did an interesting analysis of a memory leak in jscript (internet explorer) when there are "circular" references between DOM objects and (real) jscript objects:...
44
by: Steven T. Hatton | last post by:
This may seem like such a simple question, I should be embarrassed to ask it. The FAQ says an object is "A region of storage with associated semantics." OK, what exactly is meant by "associated...
3
by: RobG | last post by:
I am playing with a script that will allow columns of a table to be moved by dragging them left or right. To do this with functions is fairly straight forward, however after looking at Richard...
5
by: Robert Zurer | last post by:
I have a large pool of business objects all referencing one another in various ways. In the client application I want to do something like employee.Delete(); Behind the scenes, I want to...
8
by: Brian Sarka | last post by:
Okay, Maybe I've been at this longer than most and my experience has been shaped by languages and terminology that didn't change for decades at a time but there is one thing that bothers me enough...
5
by: Michael Moreno | last post by:
Hello, In a class I have this code: public object Obj; If Obj is a COM object I would like to call in the Dispose() method the following code: ...
16
by: anonymous.user0 | last post by:
The way I understand it, if I have an object Listener that has registered as a listener for some event Event that's produced by an object Emitter, as long as Emitter is still allocated Listener...
275
by: Astley Le Jasper | last post by:
Sorry for the numpty question ... How do you find the reference name of an object? So if i have this bob = modulename.objectname() how do i find that the name is 'bob'
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: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
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
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
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
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,...

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.