Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Array of references

How can I do something like this?

int v1 = 4;
int v2 = 3;
int v3 = 2;
int v4 = 1;

int [] vars = new int [] {ref v1, ref v2, ref v3, ref v4};

for (var i = 0; i < 4; i++) {
    ChangeVar (vars [i], i);
}

void ChangeVar (ref int thatVar, int newValue) {
    thatVar = newValue;
}

Edit:

I want to do this because those variables are accessed directly by other classes. Such as v1 could be the width of something and v2 could be the height of something. Some of my classes use the width variable to limit the length of the input it has to get from the user. Some classes use the height variable to do something else. But I want to be able to edit those variables using a loop because right now this is how the edit process works:

int indexOfVarToChange = GetIndex ();

switch (indexOfVarToChange) {
    case 0:
        int newValue = GetNewValue ();
        width = newValue;
        break;
    case 1:
        int newValue = GetNewValue ();
        height = newValue;
        break;
}

I have to manually reassign the variables because I can't have an array of references to those variables to use in a loop. I have over 30 unique variables that I have to do this for and it's a pain.

I guess the fallback plan would be to move all those variables into a Dictionary and have an array of all the keys and pass each key to the editing function.

like image 208
TreeTree Avatar asked Sep 19 '11 14:09

TreeTree


2 Answers

No you can not.

You can still edit the elements in place, but only by assigning directly into them:

 vars[2] += 42;

But I just tested this works:

using System;
public class Test
{
        private static void assign(ref int i)
        {
             i = 42;
        }

        public static void Main()
        {
              var vars = new [] { 1,2,3,4 };
              Console.WriteLine(vars[2]);
              assign(ref vars[2]);
              Console.WriteLine(vars[2]);
        }
}

See it LIVE http://ideone.com/fz36y

Output

3
42

Update: Wrapper

As a mental exercise, I came up with this sick-and-twisted mechanism to still get what you want (but at even more cost than simply boxing all the ints):

private class Wrap<T> where T : struct
{
    public T Value;

    public static implicit operator Wrap<T>(T v) { return new Wrap<T> { Value = v }; }
    public static implicit operator T(Wrap<T> w) { return w.Value; }

    public override string ToString() { return Value.ToString(); }
    public override int GetHashCode() { return Value.GetHashCode(); }
    // TODO other delegating operators/overloads
}

Now, a Wrap<int> will behave roughly as a regular int (needs more work in the field of comparison, equality and operators). You can use it to write this, and have it work the way you wanted:

private static void assign(ref int i)
{
    i = 42;
}

public static void Main()
{
    Wrap<int> element = 7;
    var vars = new Wrap<int>[] {1, 2, element, 3, 4};
    Console.WriteLine(vars[2]);
    assign(ref vars[2].Value);
    Console.WriteLine(element);

    Console.ReadKey();
}

Output:

7
42

See it live too: http://ideone.com/b0m7T

like image 133
sehe Avatar answered Oct 05 '22 23:10

sehe


Assuming for the sake of argument that you really do need to do something like this, I think the closest you can get without using unsafe code is to change your code to add a level of indirection by making a little class Holder which "holds" ints (or any T)

namespace ConsoleApplication33 {
  public static class Program {
    private static void Main() {
      var t1=new Holder<int>(4);
      var t2=new Holder<int>(3);
      var t3=new Holder<int>(2);
      var t4=new Holder<int>(1);

      var vars=new[] {t1, t2, t3, t4};

      for(var i=0; i<4; i++) {
        ChangeVar(vars[i], i);
      }
    }

    static void ChangeVar<T>(Holder<T> thatVar, T newValue) {
      thatVar.Value=newValue;
    }

    public class Holder<T> {
      public T Value { get; set; }

      public Holder(T value=default(T)) {
        Value=value;
      }
    }
  }
}
like image 21
Corey Kosak Avatar answered Oct 06 '22 01:10

Corey Kosak