System.Linq错误InvalidOperationException:在Queue.Average上

时间:2018-05-01 15:56:56

标签: c# linq unity3d

使用队列平均9个浮点值的集合。偶尔(它通常有效!)我收到以下错误

  

InvalidOperationException:由于当前操作,操作无效   对象的状态System.Linq.Enumerable.Average(IEnumerable`1   源)

违规行是此代码摘录中的最后一行

private bool OnPersonUpdated(IEvent evt)
{
    Event_Update castEvent = evt as Event_Update;
    if (castEvent != null)
    {
        if (peopleDict.ContainsKey(castEvent.id))
        {
            float xVel = castEvent.velX;
            GameObject cubeToMove = peopleDict[castEvent.id];
            if (xVel > 0)
            {
                float xPos = -1f * positionForPerson(castEvent.person);

                float dif = xPos - _prevX;
                if (dif < .5f)
                {
                    _posQueue.Enqueue(xPos);
                }
                if (_posQueue.Count >= 10)
                {
                    _posQueue.Dequeue();
                }
                float avPos = _posQueue.Average();

我意识到,如果没有提供完整的应用程序很难分析发生了什么,但我应该尝试哪些故障排除步骤?

1 个答案:

答案 0 :(得分:2)

这会发生(1)因为您的队列正在与迭代同时修改;这是导致队列迭代器抛出InvalidOperationException的唯一条件,或者(2)你的队列没有元素,元素类型是不可为空的。

(1)考虑找到Queue<T> here的参考源代码。这是抛出异常的代码中的位置(第369行):

if (_version != _q._version) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
_q.version实例被修改时,

Queue<T>会更新; _version类的实例变量Queue<T>.Enumerator在您开始迭代时存储Queue<T>的版本。

您可以通过在读取和更新周围添加一些锁定,或切换为使用ConcurrentQueue<T>来解决此问题。

(2)考虑Enumerable<T>找到here的参考源代码。平均float(第2002行)和float?(第2016行)的代码在处理空集合的方式上有所不同:可空版本返回null,而非可空版本则抛出异常。您可以通过在获取平均值之前将队列元素强制转换为float?来解决此问题:

float? avPos = _posQueue.Cast<float?>().Average();

显然,此更改要求您对avPos进行无效检查。