Objects and references
In the theme on arrays, the assignment int[] b = a; did not create a second array but gave the first one another name. Objects of classes behave the same way:
var a = new House("red");
House b = a;
b.Color = "blue";
Console.WriteLine(a.Color); // blue
class House
{
public string Color { get; set; }
public House(string color) => Color = color;
}Let's go through it line by line:
var a = new House("red");builds a red house and gives it the namea.House b = a;does not build a second house. Now the same house has two names:aandb.b.Color = "blue";repaints this one house.- That is why
Console.WriteLine(a.Color)printsblue:aandbshow the same house.
Picture a house standing on a street, and in your pocket a slip of paper with its address. The variable House a is the slip, not the house. The line House b = a; copies the address onto a second slip: there are now two slips, but still one house. Whoever comes to that address to paint it, the very same house gets painted.
The variable holds a reference
A class is a reference type, like an array. The object sits in memory on its own, and the variable holds a reference to it: that address on the slip. Assignment copies what the variable holds, so b = a copies the address, not the house.
In the widget, an object variable shows an arrow and a short form of the object instead of a value. → House { Color = "red" } reads like this: the variable leads to a house whose Color is "red". Press "Next step" and read the caption: it says whether the names share one house.
1var a = new House("red");2House b = a;3b.Color = "blue";4Console.WriteLine(a.Color);5Repaint(a);6Console.WriteLine(b.Color);7b = new House("red");8Console.WriteLine(a.Color);9Console.WriteLine(b.Color);10 11void Repaint(House h)12{13 h.Color = "green";14}15 16class House17{18 public string Color { get; set; }19 20 public House(string color)21 {22 Color = color;23 }24}
A house is built, and the variable a gets a reference to it.
As long as two variables hold one reference, a change through either name is visible through the other. A method that is passed an object gets one more copy of the reference and changes the same house. Interviewers often ask what happens after b = a if the type of a is a class. The answer: both variables lead to one object, and changes through one are visible through the other.
The slip can be rewritten
The address on a slip can be erased and a new one written. After b = new House("red"), the variable b leads to a new house and a to the old one. The old house does not change: assigning to a variable does not touch the object.
The same goes for a method parameter. If you write h = new House("pink"); inside Repaint, only the copy of the reference in h changes. The variable a in the calling code still leads to the old house.
A reference to nowhere: null
Here the slip and the reference differ. On a slip you can get the address wrong and end up at another house. A reference in C# cannot be spoiled like that: it either leads to a real object or is empty.
An empty reference leads to no object and is written as the word null. It is a slip with no address written on it. Such a reference can sit in a variable or in an element of an array whose elements are of a reference type, such as House:
House[] street = new House[3];
Console.WriteLine(street[0] == null); // True
street[0] = new House("red");
Console.WriteLine(street[0].Color); // red
Console.WriteLine(street[1] == null); // True
class House
{
public string Color { get; set; }
public House(string color) => Color = color;
}An array of numbers new int[3] is filled with zeros, and an array of houses new House[3] with empty references. These are three slips without addresses: not a single house has been built yet. A house appears only when the result of new is put into an element.
Comparing with ==
For objects of the classes you write yourself, == compares references, as it does for arrays: it checks whether it is one house, not whether the houses are alike.
var a = new House("red");
var b = new House("red");
House c = a;
Console.WriteLine(a == b); // False
Console.WriteLine(a == c); // True
class House
{
public string Color { get; set; }
public House(string color) => Color = color;
}a and b have the same color, but they are two different houses at two addresses, so a == b gives false. And c is a second slip with the address of house a, so a == c gives true.
Common mistake
An array of objects was created, but the objects themselves were not:
House[] street = new House[3];
street[0].Color = "red"; // ✗
Console.WriteLine(street[0].Color);
class House
{
public string Color { get; set; }
public House(string color) => Color = color;
}Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.The program compiles, but when it runs it stops at the second line with a NullReferenceException. street[0] holds null: there is no address, so there is nowhere to go to paint. The compiler gives no warning here: it does not track which elements of an array have already got objects. Build the house first: street[0] = new House("red");.
Key points
- A variable whose type is a class holds a reference to an object:
House b = a;copies the reference and gives the same object a second name. - A change to an object through one name is visible through all the others; a method that gets an object changes that same object.
- Assigning a new reference to a variable,
b = new House("red"), changes only that variable, not the object. nullis a reference that leads nowhere: using a field or a property through it stops the program with aNullReferenceException.