
You mean other than the fact that is _is_ a value type? :)
The short answer is: because it is a "struct" and not a "class".
That's the mechanical explanation for why it is a value type. I am not
sure what other answer you might be expecting. I mean, I could use the
behavior of System.Int32 to argue that is why it is a value type. But in
reality, it is the other way around. That is, it has that behavior
_because_ it is a value type. The only thing that "makes it a value
type" is the fact that that is how it was implemented in the language and
framework.
Unfortunately, I think you do not really have a full understanding of the
concepts of a variable, versus a value type or reference type. it is
hard in this context to provide a good explanation ? the forum is not
really interactive enough for a proper discussion ? but I will try my best.
As I mentioned before, a variable is always mutable (in C#?in other
languages this is not necessarily true). And yes, the _variable_ can be
thought of as "a changeable place in memory where a value has been placed".
it is unfortunate that the words "value" and "reference" have slightly
different meanings depending on the context. But, they do. So
hopefully by pointing that out, I can use those words in their different
ways without making the explanation too confusing. With that said, here
goes nothin'? :)
The question of "value type" versus "reference type" has nothing to do
with the variable per se, but rather what that "value" that is in the
variable is. Note that all variables have a "value", even variables
that hold a "reference type". This is what I mean by the use of the
words in multiple ways.
Now, a variable holding a value type has as its value the value type
itself. The storage allocated for the variable _is_ the value type
instance itself. You can modify the contents of that storage by
assigning a new instance of a value type to the variable. Or, if the
value type is mutable, you can do something that will ultimately modify
a field in the value type (assign to the field, or call a method or
property that assigns to the field).
But in this case, the storage the variable represents is modified _only_
if you are using that variable representing the value type itself. Any
other way of getting the value type instance (e.g. returned from a
property) will create a copy of the original value, and the operation
will modify the copy, not the value in the original storage location.
A variable holding a reference type has as its value the _reference_ to
the instance of that type, which is actually stored elsewhere. The
storage allocated for the variable is only that reference, while the
storage for the reference type instance is elsewhere (i.e. the heap).
For a reference type variable, if you modify the contents of the
variable, you are simply copying a different reference into the
variable. Nothing happens to the object that variable was previously
referencing. Conversely, if you modify the object the variable was
referencing, you will see that modification immediately when accessing
the instance via that variable _and_ via any other variable that was
referencing that same instance, while nothing at all happens to the
variable's value itself.
So, when we look at the type System.Int32 (i.e. "int"), because it is
declared as a "struct" and not a "class", it is by declaration and by
definition a value type. This gives it the specific value type behavior
described above.
Furthermore, there is nothing in the System.Int32 struct that allows you
to modify an instance of System.Int32. The only thing you can ever do
is assign a new value of System.Int32 to a variable of that type. This
does mutate the _variable_, but not the original instance of
System.Int32 the variable used to hold. A whole new instance of
System.Int32 is copied into the variable.
Thus, System.Int32 is a value type (because it is declared as "struct")
and it is immutable (because there is nothing in the type that allows you
to modify an instance of the type?you can only copy a new instance over
an old one).
I will now digress a bit? :)
I think part of the problem is that because many programmers are so used
to using primitive types without ever thinking about mutability or
immutability, their internal conceptualization of the behavior of the
types is too imprecise. I know that happened to me when I starting
using C# after years of C++.
The same concepts of mutability can apply in other languages, such as
C++. But C++ does not provide the same kind of clear division between
value types and reference types. Instead, any given structure or class
can act as either, depending on usage.