13

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.

asked Sep 19, 2011 at 14:09
4
  • Why do you want to do this? Can’t you pass the array and an index? Commented Sep 19, 2011 at 14:10
  • 2
    @TreeTree: It's called int*... Commented Sep 19, 2011 at 14:11
  • @Mehrdad: creative thinking. However as you are well aware there are a number of caveats with pointer lifetime that I doubt the OP is aware of Commented Sep 19, 2011 at 14:13
  • unless you want to descend into the unsafe inferno, you can't. To be honest I don't see why you would even want to, as you could just use the array to hold v1 through v4 and nothing weird would be necessary. Commented Sep 19, 2011 at 14:13

3 Answers 3

6

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

answered Sep 19, 2011 at 14:12

Comments

3

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;
 }
 }
 }
}
answered Sep 19, 2011 at 14:25

2 Comments

We had the same idea, however, my version contains implicit conversions and forwarding of GetHashCode and ToString as a start of making things transparent :)
I would suggest that Value should be a field rather than a property. While most classes' fields represent implementation details that should not be exposed to the client, I would suggest that the whole purpose of a Holder<T> to hold and expose its value, much as an array exposes its elements. Exposing the field doesn't meaningfully constrain the design of the class, but wrapping it in a property makes it impossible to do useful things like either MyPointHolder.Value.X += 3; or Threading.Interlocked.Increment(ref CounterHolder.Value);.
0

The InitializeAll method of this class works by using Linq expressions and reflection. It's the same intent as the code you want, I think. It initializes v1, v2, v3, and v4 to 0, 1, 2, and 3 respectively.

using System;
using System.Linq.Expressions;
namespace ArrayOfReferences
{
 public class InitializeMultipleVariables
 {
 int v1;
 int v2;
 int v3;
 int v4;
 public void InitializeAll()
 {
 Initialize(
 () => v1, 
 () => v2, 
 () => v3, 
 () => v4);
 }
 public void Initialize(params Expression<Func<int>>[] intExpressions)
 {
 for (int i = 0; i < intExpressions.Length; i++)
 {
 var expr = intExpressions[i].Body as System.Linq.Expressions.MemberExpression; 
 var fieldInfo = this.GetType().GetField(expr.Member.Name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
 fieldInfo.SetValue(this, i);
 }
 }
 }
}
answered Oct 22, 2013 at 9:24

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.