1

Possible Duplicate:
How do I assign by “reference” to a class field in c#?

I want to copy the reference of my value type to another value type. Is it possible without using unsafe paradigm?

int a = 10;
int b = 15;
a = b; // BUT I WANT TO SET REFERENCE OF b !

Here is my real example. I create enum value type and send it as parameters by reference:

   public enum Test
{
    test1,
    test2,
    test3
}

public class MyTestClass1
{
    private Test _test;

    public MyTestClass1(ref Test test)
    {
        _test = test;
    }
}

public class Content
{
    public void Method()
    {
        Test e = Test.test1;
        /*some code*/
        var omyTestClass1 = new MyTestClass1(ref e);
        /*some code*/
        e = Test.test2;
        /*some code*/
        e = Test.test3;
    }
}
Community
  • 1
  • 1
andDaviD
  • 555
  • 1
  • 11
  • 26

4 Answers4

1

You can't do this without using unsafe or wrapping your value type inside a struct/class.

From MSDN:

Assigning one value type variable to another copies the contained value.

RB.
  • 36,301
  • 12
  • 91
  • 131
1

It is not possible to have a local variable that contains a reference to another local variable in the same method. A similar situation that is possible is for a method parameter to have a reference to a local variable in the calling method:

void CallingMethod()
{
    int a = 10;
    SomeMethod(ref a);
    ...
}

void SomeMethod(ref int b)
{
    // here, the variable b holds a reference to CallingMethod's local variable "a".

Note that b could hold a reference to something other than a local variable. For example, you could call SomeMethod like this, in which case the reference would point to a field of an object on the heap:

class MyClass
{
    private int _a;
    public void AnotherCaller()
    {
        SomeMethod(ref _a);
        ...
    }
}

Update: Eric Lippert has occasionally written about the feature you're asking about, because the CLR does support it, and C# could support it. See this answer, for example: https://stackoverflow.com/a/4923772/385844

Community
  • 1
  • 1
phoog
  • 42,068
  • 6
  • 79
  • 117
1

I'm not sure I understand you completely, but you could just wrap your int inside some reference type, like an int[] of length 1, or a 1-tuple, Tuple<int>.

So:

var a = Tuple.Create(10);
var b = Tuple.Create(15);
a = b;

Since Tuple<> is immutable, this is quite pointless, however.

But then with:

var a = new[] { 10 };
var b = new[] { 15 };
a = b;
// a and b reference the same object, and that'a a mutable object!
b[0] = 17;
// now a and b are still the same object, so also a[0] == 17

Note: This has no connection to the ref keyword you use. You seem to use ref for no reason.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • Boxing and Unboxing http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx – John Oct 15 '13 at 13:33
  • @Abatonime Why do you bring that link here now? If you first box an `int`, then you can copy the reference to that box to another variable. Then `ReferenceEquals` will confirm that the two (reference-type) variables refer the same box. – Jeppe Stig Nielsen Oct 15 '13 at 16:51
  • I posted this link because what you described in your answer looks like Boxing. So this msdn link explains Boxing more in detail. – John Oct 16 '13 at 10:04
  • @Abatonime "Boxing" an `int` is assigning it to (or passing it as) a variable of reference type, that is one of the base classes of `System.Int32`, or one of the interfaces that `System.Int32` implements. For example: `object box1 = 10; IFormattable box2 = 15; var ref2ToBox1_reusesBoxNoNewBoxing = (IConvertible)box1;` – Jeppe Stig Nielsen Oct 16 '13 at 14:48
1

What if your method was in fact:

public MyTestClass1 Method()
{
    Test e = Test.test1;
    /*some code*/
    var omyTestClass1 = new MyTestClass1(ref e);
    /*some code*/
    e = Test.test2;
    /*some code*/
    e = Test.test3;
    return omyTestClass1;
}

The value returned contains a reference to a value type that had been on the stack, but now isn't. Now if you try to access that field, you can get anything.

Worse, what if you write to that reference? If that reference had been stored on the actual call-stack, rather than spending all its time in registers (and we are probably safe in assuming that the very fact that there was a field in a class referring to it meant that it had to be there), well what's there now? It could be a reference to an object. It could be a return address. Writing to it could cause some strange fandango-on-the-core bug, quite possibly some time after the write and hence proving hard to debug.

We'd lose some of the basic guarantees we have. After you've written to that value, just about any code anywhere can potentially fail in some bizarre way.

It's worth noting at this point, that C++ and .NET itself (that is to say, everything you can do in .NET including some you can't in C#) which both allow local refs and return values of ref don't allow ref fields.

The closest you can come is with capturing as happens with lambdas and anonymous methods. Here locals aren't stored on the stack, but in the heap, to allow them to live as long as the lambda they are captured by lives (and get collected when the last of them is collected). You can certainly use this to maintain references to what started as a local, in an object.

Alternatively, you can use a class that does the necessary work to wrap a value type. Here for example is one I used when I had a similar enough need:

public sealed class SharedInt
{
  private int _value;
  /// <summary>Creates a new SharedInt with a value of zero.</summary>
  public SharedInt(){}
  /// <summary>Creates a new SharedInt.</summary>
  /// <param name="value">The initial value of the object.</param>
  public SharedInt(int value)
  {
    _value = value;
  }
  /// <summary>Returns the value of the SharedInt.</summary>
  public int Value
  {
    get { return _value; }
  }
  /// <summary>Returns the value of the SharedInt.</summary>
  /// <param name="ri">The SharedInt to cast.</param>
  /// <returns>An integer of the same value as the SharedInt.</returns>
  public static implicit operator int(SharedInt ri)
  {
    return ri._value;
  }
  /// <summary>Atomically increment the value of the SharedInt by one.</summary>
  /// <returns>The new value.</returns>
  public int Increment()
  {
    return Interlocked.Increment(ref _value);
  }
  /// <summary>Atomically decrement the value of the SharedInt by one.</summary>
  /// <returns>The new value.</returns>
  public int Decrement()
  {
    return Interlocked.Decrement(ref _value);
  }
  /// <summary>Atomically add a value to the SharedInt.</summary>
  /// <param name="addend">The number to add to the SharedInt.</param>
  /// <returns>The new value.</returns>
  public int Add(int addend)
  {
    return Interlocked.Add(ref _value, addend);
  }
  /// <summary>Atomically replace the value of the SharedInt, returning the previous value.</summary>
  /// <param name="value">The number to set the SharedInt to.</param>
  /// <returns>The old value.</returns>
  public int Exchange(int value)
  {
    return Interlocked.Exchange(ref _value, value);
  }
  /// <summary>Atomically subtract a value from the SharedInt.</summary>
  /// <param name="subtrahend">The number to subtract from the SharedInt.</param>
  /// <returns>The new value.</returns>
  public int Subtract(int subtrahend)
  {
    return Interlocked.Add(ref _value, -subtrahend);
  }
}

I'd a need for some atomicity guarantees that you may not, and likewise maybe didn't need some things that you do need, but it served perfectly well as a means to be able to deal with the same int value from within different classes.

If you don't mind going through a property each time, you can do a more general-purpose version.

public class TypedBox<T> where T : struct
{
  public T Value;
}

Exposing a field publicly has considerable downsides (which is why we generally never do so), but most of them don't apply to this case (we want to be able to manipulate it fully from outside) and it means that you can even pass the Value as a ref or out parameter.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251