【问题标题】:Tracking down the cause of a NaN float追踪 NaN 浮点数的原因
【发布时间】:2013-05-12 09:59:14
【问题描述】:

我有浮点数组

public float[] Outputs;

在我的代码中,某处更新了数组值并导致了 NaN。这是一个非常罕见的错误,我终其一生都无法弄清楚是什么原因造成的。

如何以最少的代码更改进行更改以追踪它?最好将该数组设为私有并重命名,然后创建一个名为 Outputs 的属性,用于获取和设置,每次设置时都会进行 NaN 检查。然后我可以在设置 NaN 并检索调用堆栈时轻松引发异常,而不是在另一段代码尝试使用它时进一步发现它。像这样的东西-实际上可以编译。

我得到错误:

"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."

这是我的代码:

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

编辑:感谢人们的回答,其他寻找答案的人可能想阅读以下内容: Why C# doesn't implement indexed properties?

【问题讨论】:

  • 你有什么问题?
  • 为什么这不起作用?
  • 我已对其进行了更新,以使问题更加清晰。我无法编译代码。

标签: c#


【解决方案1】:

您不能在 C# 中使用命名索引器,作为一种解决方法,您可以执行以下操作:

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!
...

我将其更新为更通用,因此您可以将其重新用于各种其他类型,而不仅仅是 float

【讨论】:

    【解决方案2】:

    实际上不可能用特定名称声明索引器。您必须在它周围包裹一个对象并使用:

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

    在您的情况下,您可以为这种情况使用包装类:

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

    要使用它,您需要使用ArrayWrapper-class 作为属性类型。

    作为替代方案,您可以使用扩展方法(不太好,因为您需要更改代码):

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

    并以这种方式使用它:

    targetObject.Outputs.SetFloat(0, Single.NaN);
    

    【讨论】:

    • 扩展方法建议还需要 index 作为参数传入。
    • @James Right 我做得很快就忘记了。
    猜你喜欢
    • 2012-08-29
    • 2011-12-25
    • 2012-03-09
    • 2015-10-20
    • 2019-03-17
    • 1970-01-01
    • 2012-12-06
    • 2013-05-05
    • 2012-10-19
    相关资源
    最近更新 更多