0

I have this C# code:

int i = 20;

object t = i;

object r = t;

r = 100;

Why at this point, the value of T is still 20 and not 100 ?

I supposed T and R pointed to the same location and changes to any of them should affect each other...

I can't really understand how reference types work in the Heap, please help me

Alessandro
  • 131
  • 1
  • 9

2 Answers2

3

Why at this point, the value of T is still 20 and not 100 ?

Because you didn't modify t.

You'll want to look up "boxing". But, what's going on in your code is that the value 20 stored in i is "boxed", which means a new reference type object is allocated and the value 20 is copied into that object.

When you assign r = t, you copy the reference of that boxed value to t. So far, so good.

But, when you assign r = 100;, you have not modified the boxed value. The original boxed value remains the same, but now is referenced only by t.

The assignment r = 100 creates a whole new boxed value, allocated on the heap, and copies the reference to that object into the variable r. This has no effect on t, which remains set to the reference of the first boxed value of 20.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • 1
    Boxed value types are not immutable. Them can provide methods, which mutate boxed value, although most of them do not do so. – user4003407 Oct 28 '17 at 08:13
  • @PetSerAl: interesting. Thanks for clarifying that. I overlooked the possibility, because normally a boxed value is referenced via `System.Object`, which of course doesn't expose any of the underlying functionality of the boxed object. It didn't occur to me it would be possible to access the value at all except to unbox it, never mind modify it. But a quick test shows that via reflection, one can in fact get access to the boxed value type's members and actually manipulate it. And I suppose internal mechanisms (e.g. a running timer) could do the same. I will edit to fix that error. – Peter Duniho Oct 28 '17 at 08:27
  • 1
    Actually, I am not thinking of reflection, when I write this. Interface methods can be called without unboxing objects. For example: calling `IEnumerator.MoveNext` on boxed `List.Enumerator` will advance boxed enumerator to next item. – user4003407 Oct 28 '17 at 08:31
  • @PetSerAl: yes, that's another route into the boxed object. Interestingly, I followed up on my "running timer" scenario, and discovered that `async` methods in a mutable value type are potentially bad (*). That is, because the state engine generated creates a new copy of the value for each `await`, if one starts the timer from e.g. an interface method in the type on a boxed value, code holding the reference to the original boxed value won't see any changes. That scenario works fine if the operation is done in a single thread (e.g. `Thread.Sleep()` with changes to the value). – Peter Duniho Oct 28 '17 at 08:52
  • (*) That is, worse than mutable value types are in the first place. :) – Peter Duniho Oct 28 '17 at 08:52
  • Q&A related to that last point (`async` methods on mutable value types) include: https://stackoverflow.com/questions/31642535/structs-private-field-value-is-not-updated-using-an-async-method and https://stackoverflow.com/questions/24811287/how-to-deal-with-side-effects-produced-by-async-await-when-it-comes-to-mutable-v – Peter Duniho Oct 28 '17 at 08:57
  • Thank you Peter... now it's really clear to me ! :-) – Alessandro Oct 28 '17 at 13:30
0

When you set integer value i to an object t, boxing occurs and integer value inside a box put into Heap.

When you set t as r = t, at that time they point to same reference address on the Heap. But when you set r like r = 100 with a new integer value, new boxing occurs and r will be pointing to a different address.

First of all, boxing and unboxing is very costly thing. Why are you trying to set integer to object?

If you want to pass integer to some method and get changed value you can use ref keyword in the method argument.

Here below you can find sample code:

    public int GetValue() {
        int i = 20;
        SetNewValue(ref i);
        return i;
    }

    public void SetNewValue(ref int value) {
        value = 100;
    }
Nazim
  • 639
  • 2
  • 10
  • 26
  • first of all, thank you for the clarification. I wasn't trying to set integer to object for a precision reason in particular. It was just a sample code for testing purpose, because i was desperately trying to understand how reference types work and i couldn't get it until your good example ! – Alessandro Oct 28 '17 at 13:27