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?

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
Gio
  • 4,099
  • 3
  • 30
  • 32
  • Also see this: http://stackoverflow.com/questions/4542536/is-it-possible-to-return-a-reference-to-a-variable-in-c/4542706#4542706 – Betamoo Dec 28 '10 at 15:56

7 Answers7

7

UPDATE: The feature discussed below was finally added in C# 7.


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. See http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/ for details.

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.

See also the related question: Why doesn't C# support the return of references?

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • I've seen this idiom employed for command line tools which either read from a file passed as parameter or stdin: `std::istream& is = blah() ? ifs : std::cin`. I would call a function with either `ifs` or `std::cin`, but others seem to be averse to extra function calls. – sbi Jul 19 '10 at 21:01
  • @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 Jul 19 '10 at 22:15
  • 1
    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 Jul 19 '10 at 22:51
5

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
Community
  • 1
  • 1
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
2

If all you need is to modify a value type within a function, then pass the parameter with the ref keyword.

int i = 0;

void increment(ref int integer)
{
    integer++;
}

increment(ref i);

Matt H
  • 7,311
  • 5
  • 45
  • 54
  • Don't want to have to tear apart a function into subfunctions just to use a reference. thanks anyway. – Gio Jul 19 '10 at 20:42
  • @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` type (clever idea, `+1` from me) and a function taking an argument by `ref`, I'd certainly prefer a function. – sbi Jul 19 '10 at 21:04
2

Yes you can do that with C# 7.0. It has support for returning references and storing references. See my answer here.

Community
  • 1
  • 1
CodingYoshi
  • 25,467
  • 4
  • 62
  • 64
1

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
  • 15,179
  • 13
  • 69
  • 123
1

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...

Community
  • 1
  • 1
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
1

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
  • 17,549
  • 5
  • 55
  • 73