2

I've got float array

public float[] Outputs;

Somewhere in my code, something is updating the array values and causing a NaN. This is a very infrequent error and I can't work out for the life of me what's causing it.

How can I make a change with minimal code alteration to track it down? It'd be good to make that array private and rename it, then create a property called Outputs for getting and setting that does a NaN check every time it's set. Then I can easily raise an exception when the NaN is set and retrieve a call stack, rather than discovering it further down the line when another piece of code tries to use it. Something like this - that actually compiles.

I get the error:

"Bad array declarator: To declare a managed array the rank specifier precedes 
 the variable's identifier. To declare a fixed size buffer field, use the fixed 
 keyword before the field type."

Here is my code:

    public float[] _outputs;

    public float Outputs[int index]   
    {
        get
        {
            return _outputs[index];
        }
        set
        {
            if (float.IsNaN(value))
                throw new Exception("Blar blar");
            _outputs[index] = value;
        }
    }

EDIT: Thanks for an answers people, anyone else looking for answers may want to read this: Why C# doesn't implement indexed properties?

Community
  • 1
  • 1
Will Calderwood
  • 4,393
  • 3
  • 39
  • 64

2 Answers2

4

You can't use named indexers in C#, as a workaround you could do something like:

public class Indexer<T>
{
    private T[] _values;

    public Indexer(int capacity)
    {
        _values = new T[capacity];
    }

    protected virtual void OnValueChanging(T value)
    {
        // do nothing
    }

    public T this[int index]
    {
        get { return _values[index]; }
        set
        {   
            OnValueChanging(value);
            _values[index] = value;
        }
    }
}

public class FloatIndexer : Indexer<float>
{
    public FloatIndexer(int capacity)
        : base(capacity)
    {
    }

    protected override void OnValueChanging(float value)
    {
        if (float.IsNaN(value))
            throw new Exception("Blar blar");
    }
}

public class Container
{
    public Container()
    {
        Outputs = new FloatIndexer(3);
    }

    public FloatIndexer Outputs { get; private set; }
}
...
var container = new Container();
container.Outputs[0] = 2.5f;
container.Outputs[1] = 0.4f;
container.Outputs[2] = float.NaN; // BOOM!
...

I updated this to be more generic so you could re-use it for various other types, not just float.

James
  • 80,725
  • 18
  • 167
  • 237
2

Actually it's not possible to declare a indexer with a specific name. You must wrap a object around it and use:

public float this[int index] { ...}

In your case you could use a wrapper class for this case:

public class ArrayWrapper
{
    public float this[int index] { ...}
    public ArrayWrapper(float[] values) { .... }
}

To use it you need to use the ArrayWrapper-class as property type.

As alternative you could use a extension method ( Not so fine because you need to change code ):

public static void SetFloat(this float[] @this, int index, float value) { ... }

And use it this way:

targetObject.Outputs.SetFloat(0, Single.NaN);
Felix K.
  • 6,201
  • 2
  • 38
  • 71