backtrack
backtrack

Reputation: 8154

C# struct and class variable value

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

  1. it is class : output is 2

  2. it is struct :output is 12

Can any one explain me?

Thanks

Upvotes: 1

Views: 221

Answers (4)

supercat
supercat

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

Henk Holterman
Henk Holterman

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

Eugene
Eugene

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

Daniel
Daniel

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

Related Questions