Ошибка System.Linq InvalidOperationException: на Queue.Average

Использование очереди для усреднения коллекции из 9 значений с плавающей запятой. Время от времени (обычно это работает!) Я получаю следующую ошибку

InvalidOperationException: Operation is not valid due to the current state of the object System.Linq.Enumerable.Average(IEnumerable`1 source)

Оскорбительная строка является последней в этом фрагменте кода.

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();

Я понимаю, что без предоставления полного приложения трудно сказать, что происходит, но какие шаги по устранению неполадок мне следует попробовать?

Если вы используете очередь, коллекция, скорее всего, будет использоваться другим ресурсом / потоком. Без более подробной информации об объекте очереди сказать невозможно. Но в сообщении об ошибке указывается, что объект находится в недопустимом состоянии, и это может означать, что объект был добавлен / удален, когда вы выполняли метод Average.

Franck 01.05.2018 18:00

Я обновил свой пост дополнительным кодом ...

Bachalo 01.05.2018 18:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
400
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это происходит либо (1) потому, что ваша очередь изменяется одновременно с итерацией; это единственное условие, которое заставляет итератор очереди генерировать InvalidOperationException, или (2) ваша очередь не имеет элементов, а тип элемента не допускает значения NULL.

(1) Рассмотрим исходный код ссылки для Queue<T>, найденный здесь. Вот место в коде, генерирующее исключение (строка 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>, найденный здесь. Код для усреднения float (строка 2002) и float? (строка 2016) отличается тем, как они обрабатывают пустые коллекции: версия, допускающая значение NULL, возвращает null, а версия, не допускающую значения NULL, вызывает исключение. Вы можете обойти это, преобразовав элементы очереди в float? перед усреднением:

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

Очевидно, это изменение требует от вас нулевой проверки avPos.

Хотя в этом случае сообщение об исключении отличается от того, что было опубликовано OP. Кроме того, Average выбрасывает InvalidOperationException, когда очередь пуста (также с другим сообщением, чем отправленное).

Evk 01.05.2018 18:14

Спасибо за большую помощь. Я думаю, что моя цель теперь должна быть очевидна из моего обновленного образца кода> постоянно усреднять коллекцию из 10 самых последних значений с плавающей запятой в цикле событий. Вместо этого попробую ConcurrentQueue ...

Bachalo 01.05.2018 18:16

К сожалению, в моно-фреймворке, похоже, нет класса ConcurrentQueue в mscorlib :( answers.unity.com/questions/1375947/… Может ли кто-нибудь помочь с повторным «добавлением блокировки чтения и обновления» ??

Bachalo 01.05.2018 18:34

@Evk Похоже, что mono добавила поддержку параллельных очередей несколько версий назад. Если вы используете более раннюю версию, вы можете взять эталонный код и использовать его в своем собственном проекте. Добавление блокировки потребует обхода всех мест, где вы используете _posQueue, и добавления lock (_posQueue) вокруг всего блока кода, который обращается к очереди.

Sergey Kalinichenko 01.05.2018 18:50

ок, нашел кастомную очередь с блокировкой для Unity gist.github.com/jaredjenkins/5421892

Bachalo 01.05.2018 21:02

Однако отсутствует метод среднего значения. Есть ли шанс, что кто-то может помочь? gist.github.com/jaredjenkins/5421892

Bachalo 01.05.2018 21:19

@eco_bach Попробуйте _posQueue.CopyToArray().Average()

Sergey Kalinichenko 01.05.2018 21:23

Другие вопросы по теме