One major advantage of value types like Rectangle
is that if one has n storage locations of type Rectangle
, one can be certain that one has n distinct instances of type Rectangle
. If one has an array MyArray
of type Rectangle
, of length at least two, a statement like MyArray[0] = MyArray[1]
will copy the fields of MyArray[1]
into those of MyArray[0]
, but they will continue to refer to distinct Rectangle
instances. If one then performs a statement line MyArray[0].X += 4
that will modify field X
of one instance, without modifying the X
value of any other array slot or Rectangle
instance. Note, by the way, that creating the array instantly populates it with writable Rectangle
instances.
Imagine if Rectangle
were a mutable class type. Creating an array of mutable Rectangle
instances would require that one first dimension the array, and then assign to each element in the array a new Rectangle
instance. If one wanted to copy the value of one rectangle instance to another, one would have to say something like MyArray[0].CopyValuesFrom(MyArray[1])
[which would, of course, fail if MyArray[0]
had not been populated with a reference to a new instance). If one were to accidentally say MyArray[0] = MyArray[1]
, then writing to MyArray[0].X
would also affect MyArray[1].X
. Nasty stuff.
It's important to note that there are a few places in C# and vb.net where the compiler will implicitly copy a value type and then act upon a copy as though it was the original. This is a really unfortunate language design, and has prompted some people to put forth the proposition that value types should be immutable (since most situations involving implicit copying only cause problems with mutable value types). Back when compilers were very bad at warning of cases where semantically-dubious copies would yield broken behavior, such a notion might have been reasonable. It should be considered obsolete today, though, given that any decent modern compiler will flag errors in most scenarios where implicit copying would yield broken semantics, including all scenarios where structs are only mutated via constructors, property setters, or external assignments to public mutable fields. A statement like MyArray[0].X += 5
is far more readable than MyArray[0] = new Rectangle(MyArray[0].X + 5, MyArray[0].Y, MyArray[0].Width, MyArray[0].Height)
.