Question

I did the following example in c#

    interface IChangeable
    {
        void Change(params Int32[] array);
    }

    struct SomeValueType : IChangeable
    {
        private Int32 m_X;

        public SomeValueType(int X)
        {
            m_X = X;
        }

        public void Change(params Int32[] array)
        {
            m_X = array[0];
        }

        public override string ToString()
        {
            return String.Format("Crt value of m_X: {0}", m_X);
        }
    }

And in Main:

    static void Main(String[] args)
    {
        SomeValueType someValueType = new SomeValueType(5);
        Console.WriteLine(someValueType);                                   // No boxing occured. It showed: 5

        Object someRefType = someValueType;                                 // Boxed
        Console.WriteLine(someRefType);                                     // Also Shows 5 (from heap)

        someValueType.Change(2);                                            // Change Value of x not o's
        Console.WriteLine(someValueType + " " + someRefType);               // 2 5

        ((SomeValueType)someRefType).Change(3);                             // Copies to a temp stack so no change ocuured in o
        Console.WriteLine(someRefType);                                     // 5

        IChangeable itfStackChange = (IChangeable)someValueType;
        itfStackChange.Change(7);
        Console.WriteLine(someValueType);                                   // Shows 2 and not 7 ... why?

        IChangeable itfChange = (IChangeable)someRefType;
        itfChange.Change(1);                                                // Unboxes the value of o, making the value of x 1 boxes o again?
        Console.WriteLine(someRefType);                                     // Shows 1
    }

Now I am wondering what happens when I do:

        IChangeable itfStackChange = (IChangeable)someValueType;      //value was 2 and its still 2
        itfStackChange.Change(7);
        Console.WriteLine(someValueType);  

But if I change the definition of struct to class like in:

class SomeValueType : IChangeable

It writes 7 and not 2.

Was it helpful?

Solution

Value types semantics are such that the value gets copied on assignment. This means that when you change after assignment, the variables point to different objects.

For reference types the reference gets copied, meaning that when you change after assignment, both variables point to the same object.

See Value Types and Reference Types on MSDN.

OTHER TIPS

A structure-type definition actually defines two kinds of things: a kind of storage location, and a kind of heap object which inherits from the abstract class System.ValueType. The heap object effectively has one field of the corresponding storage-location type, but exposes all the members of that storage-location type as though they were its own. To the outside world, the heap type will behave like a class object; internally, however, references to this are references to its field of the corresponding storage-location type.

Although C# defines the term "inheritance" in such a way as to pretend that the storage-location type and the heap-object type are one and the same, the two types will behave differently. Casting a value type to an interface that it represents will generate a new heap object which holds a copy of the public and private fields of the value type that was cast, and then return a reference to that new instance. The resulting reference will exhibit reference semantics, since it will be a reference.

If one regards heap objects and value-type storage locations as existing in separate universes, and recognizes the cases in which values must be copied from one universe to the other, one will find that such a model will accurately predict how things will behave.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top