C# DateTime always create new object?
DateTime
is a value type - a structure.
With value types, when you do something like:
DateTime a2 = a1;
a2
gets a copy of the values of a1
. It is not the same reference to the same memory location, but a complete, separate copy.
On the other hand, Person
is a reference type - a class.
When you do:
Person p2 = p1;
With a reference type, the reference that p2
points to is the same one that p1
points to. So changes in one are changes to both.
See Value Types and Reference Types on MSDN.
As others have already pointed out DateTime
is a struct, not a class and therefore a value type. You can visualize this in the Visual Studio editor, if you change the text color used to display structs. Open the dialog in menu Tools
> Options
and navigate to Environment
> Fonts and Colors
It is helpful to change the color of delegates, enums, interfaces and structs (Value types).
In Visual Studio 2019, you can also change the look of User Members like constants or parameters.
There are two separate concepts at work here. The first is that DateTime
is a value type (a.k.a. a struct) while Person
is [presumably] a reference type (a class). Because of this, when you do:
DateTime date1 = DateTime.Now;
DateTime date2 = date1;
date2
will result in copying the value, so the two variables will not reference the same object.
With classes, when you do:
Person p1 = new Person();
Person p2 = p1;
p1
doesn't actually contain a Person
, it just contains a reference to a person. That reference is then copied (by value) to p2
. The effect of copying that reference is that both variables are now "pointing to" or "referencing" the same object.
Next there is the issue of mutability. Person
, in this case, is a mutable type. That means that it can be changed. An immutble type on the other hand cannot be changed once constructed.
The line:
p2.Age = 2;
is actually changing the object that p2
references, and since p2
and p1
both reference the same object, p1.Age
would be 2
after that line of code.
Now, for demonstration purposes, let's make an immutable Person
class:
public class Person
{
private int _age;
public Person(int someAge)
{
_age = someAge;
}
public int Age
{
get { return _age; }
}
public Person Grow()
{
return new Person(_age + 1);
}
}
If we do something like this:
Person p1 = new Person(1);
Person p2 = p1;
p2 = p2.Grow();
the second line is doing just what it was before, ensuring that both point to the same object, but the third line is different. Rather than changing (or mutating) that person to make it a year older, our Grow
method returns a new Person
object that represents someone a year older. After doing this p2
and p1
will no longer be referencing the same object; I have just changed what object p2
references to a new one that the Grow
method just created.
This second example is rather similar to what's going on with DateTime
. You can't mutate a DateTime
object; it is immutable. Calling it's methods (in this case the plus and minus operators) returns and entirely new object. By convention, value types shouldn't be mutable without some compelling reason, as it can often be tricky to deal with them. Reference types can be either immutable or mutable; neither has significant problems (in the general case).