开发者

C# Array of references

开发者 https://www.devze.com 2023-04-06 09:41 出处:网络
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};

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开发者_如何学C 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.


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


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;
      }
    }
  }
}


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);
            }
        }
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号