tags:

views:

188

answers:

6

In C++ I can do this:

 int flag=0,int1=0,int2=1;
 int &iRef = (flag==0?int1:int2);
 iRef +=1;

with the effect that int1 gets incremented.

I have to modify some older c# code and it would be really helpful if I could do something similar, but I'm thinking ... maybe not. Anybody?

+1  A: 

Fraid not. You could do it with unsafe code and pointers like so:

    int flag=0,int1=0,int2=1;
    unsafe
    {
        int *iRef = (flag==0? &int1:&int2);
        *iRef +=1;
    }

(not saying that's a good idea or anything :))

dkackman
+2  A: 
Matt
Don't want to have to tear apart a function into subfunctions just to use a reference. thanks anyway.
Gio
@Gio: I have yet to see a case where an aptly named function does not improve readability. If I have to chose between either decoding Mark's `Ref<T>` type (clever idea, `+1` from me) and a function taking an argument by `ref`, I'd certainly prefer a function.
sbi
+2  A: 

You can do it - or at least something very similar to what you want - but it's probably best to find another approach. For example, you can wrap the integers inside a simple reference type.

If you still want to do it, see the Ref<T> class posted by Eric Lippert here:

sealed class Ref<T>
{
    private readonly Func<T> getter;
    private readonly Action<T> setter;
    public Ref(Func<T> getter, Action<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }
    public T Value { get { return getter(); } set { setter(value); } }
}

public class Program
{
    public static void Main()
    {
         int flag=0,int1=0,int2=1;

         Ref<int> iRef = (flag == 0 ?
            new Ref<int>(() => int1, z => { int1 = z; }) :
            new Ref<int>(() => int2, z => { int2 = z; }));

         iRef.Value += 1;

        Console.WriteLine(int1);
    }
}

Output:

1
Mark Byers
Thankks for the tip. I'll check it out.
Gio
+1  A: 

There is no direct equivelent in C#. There are a couple of options -

You can use unsafe code and pointers as suggested by dkackman.

Another alternative is to use a reference type (class) which holds the value. For exmaple:

// Using something like
public class Wrapped<T> {
    public Wrapped(T initial) {
        this.Value = initial;
    }
    public T Value { get; set; }
}

// You can do:
bool flag=false;
var int1 = new Wrapped<int>(0);
var int2 = new Wrapped<int>(1);

Wrapped<int> iRef = flag ? int2 : int1;

iRef.Value = iRef.Value + 1;

Since you're working with references to a class, the assignment to iRef copies the reference, and the above works...

Reed Copsey
+3  A: 

The feature you want - to make managed local variable aliases is not supported in C#. You can do it with formal parameters - you can make a formal parameter that is an alias of any variable - but you cannot make a local which is an alias of any variable.

However, there is no technical difficulty stopping us from doing so; the CLR type system supports "ref local variables". (It also supports ref return types but does not support ref fields.)

A few years back I actually wrote a prototype version of C# which supported ref locals and ref return types, and it worked very nicely, so we have empirical evidence that we can do so successfully. However, it is highly unlikely that this feature will be added to C# any time soon, if ever.

I note that if I were you, I would avoid this in any language. Writing programs in which two variables share the same storage makes for code that is hard to read, hard to understand, hard to modify and hard to maintain.

Eric Lippert
sbi
@sbi: But in C# a Stream is already a reference type, so there's no problem in C#: Stream s = f ? s1 : s2;, no worries. This only becomes interesting when the variable is of *value type*, as in Gio's example. There's no way to make two *value type* locals aliases for each other in C# without using formal parameters.
Eric Lippert
@Eric: I understood that. I was just replying to your statement "Writing programs in which two variables share the same storage makes for code that is hard to read, hard to understand, hard to modify and hard to maintain." It's not always so.
sbi
+1  A: 

You could use an Action delegate like this:

int flag = 0, int1 = 0, int2 = 0;
Action increment = flag == 0 ? (Action) (() => ++int1) : () => ++int2;
increment();
Anthony Faull