References to objects

  • Thread starter Thread starter Jax
  • Start date Start date
J

Jax

I dont seem to fully comprehend references to objects yet.
Lets say for example I do this;

Customer c = new Customer();
Customer c1 = c;

I understand that if I change c1, I also change c as they
are both referencing the same piece of data.
But this isn't always the case it would seem.
Sometimes I take a reference out, change it and then go
back to the original which still has it's old value.

When does this reference copying apply and when does it
not?
I'm confused as I seem to be getting mixed results.

What I would like to know are the rules that state when it
happens and under what conditions it doesn't happen.
For example if I have an object that contains an arraylist
of customers and I grab one of those i.e:

foreach(Customer c1 in theCase.Customers)
{
if(c1.Something == something)
myCustomer = c1;
}

myCustomer.Name = "Something different";

Does this now change the customer in theCase as well?

Also on this topic, does the clone method give you a clean
version that wont effect the orignal? If not, what method
of copying would I need and how would I begin to implement
this?

Many thanks for any of you kind sirs or madames (are there
female coders?) who get me out of my muddle.

jax
 
Hi Jax,

Comments in-line.

Joe
--
http://www.csharp-station.com

Jax said:
I dont seem to fully comprehend references to objects yet.
Lets say for example I do this;

Customer c = new Customer();
Customer c1 = c;

I understand that if I change c1, I also change c as they
are both referencing the same piece of data.

Customer is a reference type (defined as a class). Both c and c1 refer to
the same object in memory. To use precise terminology, you are not changing
c1, but you are changing the state of the object that c1 refers to. Since
both c and c1 refer to the same object, you can view the changes to that
object through both references.
But this isn't always the case it would seem.
Sometimes I take a reference out, change it and then go
back to the original which still has it's old value.

You could be talking about value types, which actually copy the values from
one variable to another. Value types can be identified by the keyword
"struct" used in their definition in the Base Class Library (BCL). Many of
the built-in types, such as int and float are structs, which alias BCL types
such as System.Int32 and System.Single, respectively. The string type is a
reference type (class) and aliases the System.String BCL type. Any custom
type you define as struct is also a value type. On the other hand, if you
define a type as a class, it is a reference type and you will see reference
behavior described above.
When does this reference copying apply and when does it
not?
I'm confused as I seem to be getting mixed results.

With reference types, only the reference is copied during assignment. With
value types, the value of the type is copied.
What I would like to know are the rules that state when it
happens and under what conditions it doesn't happen.
For example if I have an object that contains an arraylist
of customers and I grab one of those i.e:

foreach(Customer c1 in theCase.Customers)
{
if(c1.Something == something)
myCustomer = c1;
}

myCustomer.Name = "Something different";

Does this now change the customer in theCase as well?

Yes, assuming that Customer is a reference type.
Also on this topic, does the clone method give you a clean
version that wont effect the orignal? If not, what method
of copying would I need and how would I begin to implement
this?

There are two ways to clone. One is to use the Object.MemberwiseClone,
which does a shallow copy. A shallow copy means that a copy is made of the
immediate object that MemberwiseClone is called on. For instance if you
have an object A that has a reference to object B and do a MemberwiseClone
to C then both A and C will be separate objects with copied state, but they
will still both refer to B because it was a shallow copy.

To get a deep copy, you should implement the IClonable interface, which
defines a Clone method. One way to do this is to use a BinaryFormatter or
SoapFormatter to serialize the type. The benefits of this are that you get
a deep copy of all objects in the object graph and it avoids circularities
because the BCL formatters are smart enough to know when they have already
serialized an object. You can then deserialize the stream into a new object
and return that as the cloned object. If such a scheme is too much for your
requirements, then you can provide another implementation of the Clone
method as you see fit. However, you should document the behavior of the
Clone for people using your type so they know what to expect. This will
help avoid semantic issues when someone using your type is trying to figure
out what you mean by a deep copy.

Joe
 
Customer c; is just a reference to a Customer object which is called c.
new Customer(); is actually the part that creates this object and once it
is created it returns the "address" to this object.

Customer c = new Customer(); is actually two operations on a single line.
The creation of the reference holder c and the a Customer object which is
nameless and invisible and can only be accessed through a reference
holder, such as c.

Customer c1 = c; is also two operations on a single line.
First it creates a new reference (holder) called c1, then we say that c1's
reference is the same one as c's.
The effect of this is that both c1 and c holds the "address" to the same
object (created with new Customer();), they reference the same Customer.

An ArrayList holds a list of references.

foreach(Customer c1 in theCase.Customers)

// for each reference in the list, treat it as a Customer reference and
call it c1

{
if(c1.Something == something)

// c1. accesses the content of the object it references to, in this casea
Customer object which has a Something property
// if the value of Something == something, set the myCustomer reference to
point the same object c1 points to

myCustomer = c1;
}

myCustomer.Name = "Something different";
// myCustomer. accesses the object it references and changes its Name
property to "Something different";

If you reran the foreach loop you would find that the object c1 (when
c1.Something == something) references to has its Name changed.

There are a few exceptions to this. Not all objects are created with the
'new' keyword.
String line = "Hello World"; will create a new String object and is
actually the same as typing
String line = new String("Hello World");
but 'line' is still just a reference to a String object. The object
itself resides somewhere in memory and once the garbage collector finds
out there are no references pointing to this object it will collect it.

(line = null; will set the reference of line to something other than the
String object that was created, so there is no reference pointing to the
String object anymore. Everyone has forgotten about the String object and
the garbage collector will spot it soon and eat it, though nobody knows
when)
 
Hi,

Simple concept is if you have a reference to a reference
type then changing the value in one will affect the
other. On the other hand, if you have reference to a
value type, then it will always make a copy of the
object, thus making a change in one object doesn't change
the other.

To know more about Reference type and value type check
out the following link.

http://msdn.microsoft.com/library/default.asp?
url=/library/en-us/vbcn7/html/vbconvaluereftypes.asp

Hope this helps...

Regards,
Madhu
 
Thanks, thats helpful to me too.

In a MS seminar there is the example

Struct SPoint {int x; int y;, ...}

SPoint sp = new SPoint(10, 20);

He says structures, unlike classes, are stack-allocated not heap-allocated.
Does this imply the rule that the only structure that can be deleted is the
last one new'd? Or does each execution of sp = new... get the same storage?

Peter Seaman
 
Joe, Morten, Madhu

I'd like to thank you all for posting up.
You confirmed the knowledge I suspected of being false to
be actually true (thank god).
I have run through the example i've been playing with and
found your comments to be fully valid (i'd forgotten a
line of code, doh!) and i'm assuming my previous confusion
in the past about references has just been due to an error
in my typing rather then my knowledge.

I did at one point implement and use the IClonable
interface but I found it not deep copying properly so I
used serialization and fixed it.
I'm assuming to use the Clone() method you do this:

public myClassObject Clone()
{
new myClassObject exampleObj = new myClassObject
(this.field1, this.field2, this.field3);
exampleObj.Field4 = this.field4;
return exampleObj;
}
//(as well as add :ICloneable to the top of the class)
which is what I tried to do, but I must have made an error
somewhere as the originals (from which I was cloning from)
were going down in value from the code that the clones
were being sent to (am I still making sense).

Thanks for clarifying this for me your the best!

jax
 
Thanks, thats helpful to me too.

In a MS seminar there is the example

Struct SPoint {int x; int y;, ...}

SPoint sp = new SPoint(10, 20);

He says structures, unlike classes, are stack-allocated not heap-allocated.

Structures aren't *always* stack-allocated. It depends where the
variable/expression occurs.

See http://www.pobox.com/~skeet/csharp/memory.html for more
information.
Does this imply the rule that the only structure that can be deleted is the
last one new'd? Or does each execution of sp = new... get the same storage?

Each would get the same storage, but there's no concept of "deleting"
objects in C#.
 
Jax said:
Joe, Morten, Madhu

I'd like to thank you all for posting up.

You're welcome. :)
I'm assuming to use the Clone() method you do this:

public myClassObject Clone()
{
new myClassObject exampleObj = new myClassObject
(this.field1, this.field2, this.field3);
exampleObj.Field4 = this.field4;
return exampleObj;
}
//(as well as add :ICloneable to the top of the class)
which is what I tried to do, but I must have made an error
somewhere as the originals (from which I was cloning from)
were going down in value from the code that the clones
were being sent to (am I still making sense).

I'm not following the "going down in value" statement. However, your code
will not compile because the Clone method of the ICloneable interface
returns type object, not the enclosing type. Additionally, the first new in
the exampleObj declaration is improper syntax. Here is some good advice Jon
Skeet put together for people posting code examples:

http://www.yoda.arachsys.com/csharp/complete.html

Joe
 
Ah yes you eyes are indeed sharper then mine joe,

I would have got those errors and fixed them.
It was conforming to the contract of the interface
correctly.

The whole value going down thing is this:

There is a method called quote.
To this method is passed a Case object which contains an
ArrayList of customer objects(amongst other things).
During this method the annual income property gets cut
down according to the amount of credit the customer has
outstanding (another arrayList inside the customer object).
e.g

foreach(Customer c1 in theCase.Customers)
{
foreach(Customer.Credit cred in c1.OutStandingCredit)
{
double takeOff = cred.MonthlyPayments * 12;
c1.IncomeDetails.AnnualIncome -= takeOff;
}
}

The problem is that the call to this method is within a
foreach loop.

foreach(Product p in alProducts)
{
Quote(p, theCase.Clone()); // Within the case clone method
it calls the customer clone() as well as many others.
}

The problem was is that it would quote the first three or
so but by then the annualIncome value would be so low that
it wouldn't be sufficient to pass the quote, meaning that
everytime it was being called it was somehow still
retaining it's value rather then having the original one
assigned to it again.

I eventually used serailization.

FormTools.Serialize(theCase, path);
foreach(Product p in alProducts)
{
theCase = (Case) FormTools.DeserializeObject(path);
Quote(p, theCase); // Within the case clone method it
calls the customer clone as well as many others.
}

Which worked but left me wondering why my cloning wasn't
working.
Any tips left? :)

jax
 
There is a method called quote.
To this method is passed a Case object which contains an
ArrayList of customer objects(amongst other things).
During this method the annual income property gets cut
down according to the amount of credit the customer has
outstanding (another arrayList inside the customer object).
e.g

foreach(Customer c1 in theCase.Customers)
{
foreach(Customer.Credit cred in c1.OutStandingCredit)
{
double takeOff = cred.MonthlyPayments * 12;
c1.IncomeDetails.AnnualIncome -= takeOff;
}
}

The problem is that the call to this method is within a
foreach loop.

foreach(Product p in alProducts)
{
Quote(p, theCase.Clone()); // Within the case clone method
it calls the customer clone() as well as many others.
}

The problem was is that it would quote the first three or
so but by then the annualIncome value would be so low that
it wouldn't be sufficient to pass the quote, meaning that
everytime it was being called it was somehow still
retaining it's value rather then having the original one
assigned to it again.

I eventually used serailization.

FormTools.Serialize(theCase, path);
foreach(Product p in alProducts)
{
theCase = (Case) FormTools.DeserializeObject(path);
Quote(p, theCase); // Within the case clone method it
calls the customer clone as well as many others.
}

Which worked but left me wondering why my cloning wasn't
working.
Any tips left? :)


I think I see the nature of your problem. You want an original set of
objects to retain their values, but you want you changes to be made only on
the cloned object. However, the same changes are reflected in both the
original objects and the clones. Am I close?

If so, the Clone() method that used serialization succeeded because it was
able to do a deep copy that included the entire object graph. However, your
implementation of Clone() did not go deep enough. You will have to make
sure that you clone the entire set of Customers *and* the entire ArrayList
of Credit objects of each customer *and* continue going down the hierarchy
for references until you have enough of the object graph cloned that you can
obtain the behavior you want. I think you are just cloning the Customer
object, but not the Credit ArrayList of each Customer, which means that the
Credit ArrayList of both the original Customer object and the cloned
Customer object refers to the same collection of Credit objects.

While the exact objects that I mention may not be exactly what you have, I
think the concept is more important. Every object that will be Cloned must
implement IClonable and you must follow references and call Clone on all the
objects in the object graph that are applicable to the problem you are
trying to solve.

I think that serialization may be the simplest solution.

Joe
 
Back
Top