delverdl
delverdl

Reputation: 83

Reference several class members

I want to access three members of a class (_orderDay, _orderCustody, _orderBox) according to and indexing variable (orderIndex), using a different approach than in the following example

public class COrdering
{
  private int _orderDay;
  private int _orderCustody;
  private int _orderBox;

  public COrdering() { _orderDay = _orderCustody = _orderBox = 0; }

  public int IncOrder(int orderIndex)
  {
     int v = orderIndex == 0 ? _orderDay : (orderIndex == 1 ? _orderCustody : _orderBox);

     v++;
     if (orderIndex == 0) _orderDay = v 
     else if (orderIndex == 1) _orderCustody = v;
     else _orderBox = v;
     return v;
  }
}

The idea is to use less coding than in the previous example. When I coded something like this in C++ I used std::bind to create a const array of references to each field involved, but I don't know how to make something similar in C#. Can anyone help me out with this?

EDIT

I've found a way to optimize IncOrder method:

//...
private int _incDay() { return ++_orderDay; }
private int _incCustody() { return ++_orderCustody; }
private int _incBox() { return ++_orderBox; }

private IReadOnlyList<Func<int>> _funcs = Array.AsReadOnly(new Func<int>[] {_incDay, _incCustody, incBox});

public int IncOrder(int orderIndex) { return _funcs[orderIndex](); }

There may be another way, such as creating an array of references to these fields, but I don't know if that's possible.

Upvotes: 2

Views: 79

Answers (3)

jjxtra
jjxtra

Reputation: 21160

Sounds like a job for an index operator overload:

public int this[int index] => IncOrder(index);

Usage:

COrdering ordering = new COrdering();
int newValue = ordering[0];

Updated - you can use an array internally

public class COrdering
{
    public enum OrderIndex { Day = 0, Custody = 1, Box = 2, NumElements };
    private readonly int[] values = new int[(int)OrderIndex.NumElements];
    public int IncOrder(OrderIndex orderIndex) => ++values[(int)orderIndex];
    public int this[OrderIndex index] => IncOrder(index);
}

Also, your constructor can be removed, in C# everything is auto initialized to 0 (or null for reference types).

Upvotes: 5

Pedro Ferreira
Pedro Ferreira

Reputation: 860

I understand you want to simplify your code, so in that case start by the variables where you save data, if you are accessing them by index it would make more sense to declare an array and use an enum, something like this:

public class COrdering
{
    enum OrderType
    {
        Day = 0,
        Custody = 1,
        Box = 2,
        Count = 3
    };

    private int[] _order = new int[(int)OrderType.Count];

    public int IncOrder(OrderType orderIndex)
    {
        // Increment corresponding order type and return its value
        return ++_order[(int)orderIndex];
    }
}

You can see that you implement your IncOrder with just one line of code. The ++ must be before the variable name, so you get the correct answer. I either use an intermediate variable for the increment or a ++ preceded of a good comment, so that the next programmer will see it.
The other solution with [] overload is unexpected and surprising for the next guy debugging your code :-) so that being said I suppose you guess which one I'd chose.

Upvotes: -1

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37050

Why not use a Dictionary<int, int>?

public class COrdering
{
     Dictionary<int, int> map = new Dictionary<int, int>();
     public COrdering() { map[0] = 0; map[1] = 0; map[2] = 0; }

     public int IncOrder(int orderIndex)
     {
         return ++map[orderIndex];
     }
}

In fact you can even use an int[] or a List<int>.

Upvotes: 0

Related Questions