Reputation: 8154
i know that struct is of value type and class is reference type but when i execute the following code why im getting the two different answer
can any one explain a bit
[struct|class] values {
public int x, y;
public values (int x, int y) {
this.x = x;
this.y = y;
}
}
values v = new values(12, 13);
object o = v;
v.x = 2;
Console.WriteLine(((values)o).x);
Outputs
when
it is class : output is 2
it is struct :output is 12
Can any one explain me?
Thanks
Upvotes: 1
Views: 221
Reputation: 81307
Given
SomeStruct s1, s2, s3;
Object o1;
... s1 gets a value somehow, then...
s2 = s1; // Q1
o1 = s1; // Q2
s3 = (SomeStruct)o1; // Q3
statement Q1 will mutate structure s2
by overwriting all of its public and private fields with the values of the corresponding fields in s1
. Statement Q2 will generate a new heap object which will act as though it contains a field of type SomeStruct
, and will modify that field by overwriting all of its fields with the corresponding fields in s1
. Statement Q3 will check whether o1
contains a "boxed" SomeStruct
and, if so, will overwrite all the fields of s3
with the corresponding ones from the boxed object.
Note that boxed structures are not usually modified while they sit within heap objects. If one were to say:
var temp = (SomeStruct)o1;
temp.someField = Whatever;
o1 = temp;
that sequence would create a new heap object which would hold a modified copy of the original structure, but the original boxed structure would remain as it was. There are, however, ways a structure within a boxed object can be modified. One should in most cases avoid using such techniques, but one should be aware there's no such thing as a non-trivial immutable structure (a struct with no fields would be immutable, but not very useful). In general, if one wants to be able to refer to a mutable instance of a structure type, it's best to encapsulate it within a simple class object, e.g.
class ExposedFieldHolder<T>
{
public T Value;
public ExposedFieldHolder(T v) {Value = v;}
}
and if one wants to have an immutable instance, one should encapsulate it in an immutable class object
class ImmutableHolder<T>
{
T value;
public T Value { get { return value; } ;
public ImmutableHolder(T v) {value = v;}
override public bool Equals(Object o) {
var other = o as ImmutableHolder<T>;
if (!other) return false;
return Object.Equals(value,other.value);
}
override public int GetHashCode() { return Object.GetHashCode(value); }
}
Upvotes: 1
Reputation: 273774
The one line that behaves very differently for struct
or class
is
object o = v;
When Values
is a reference type, o
becomes a copy of the reference v
. There still is only 1 instance of Values
.
When Values
is a value type, o
becomes a reference to the boxed copy of the instance itself. In this case the assignment creates a 2nd instance and you execute v.x = 2
on the original. The copy is not affected.
Your example includes boxing and that is an unnecessary complication, when you use values o = v;
you will get the same output. The line then creates a normal copy (2nd instance) without boxing.
To sum it up: the main difference between value and reference type is in copy semantics. You will notice different behaviour in simple assignments (x = y
) and in parameter passing (foo(x)
).
You can expect gotchas with mutable value types. As an exercise, see what f.Myvalue.x = 2;
does with Values
as class or struct with
class Foo { public Values MyValue { get; set; } }
Upvotes: 9
Reputation: 1789
Key line is
object o = v;
When values is struct (or value-type), it causes boxing values. According this (following that link, you can find exactly your question at end :))
Boxing a value of a value-type consists of allocating an object instance and copying the value-type value into that instance.
So, your value in v is copied
. When you unboxing here
Console.WriteLine(((values)o).x);
you get original v
value, not v
after
v.x = 2;
So, answer for struct (or value-types) is 12
.
For class (or reference-types) it's very simple. You are not boxing, just cast to object, so next you are working with this original v
and change it value.
Upvotes: 1
Reputation: 9521
When you use a structure and you assign it (or use it as a parameter of a method), you have a brand new copy of your structure. Whereas, with a class, you assign a reference to the class.
Upvotes: 1