Bin4ry
Bin4ry

Reputation: 732

Event subscription changed - InvalidOperationException

UI Elements can subscribe events like press, hold or release. Therefore, I created an object variable to store those information

        private Dictionary<TouchListenerType, List<Action<int, float, Vector2>>> touchData = new Dictionary<TouchListenerType, List<Action<int, float, Vector2>>>();

Every update cycle I iterate over every provided input and delegate it to the subscribers.

        try
        {
            for (int currentTouchIndex = touchCollections.Count - 1; currentTouchIndex >= 0; currentTouchIndex--)
            {
                Vector2 position = MapInput(touchCollections[currentTouchIndex].Position);
                if (touchCollections[currentTouchIndex].State == TouchLocationState.Moved &&
                    touchData[TouchListenerType.Move].Count > 0)
                    touchData[TouchListenerType.Move].ForEach(d => d.Invoke(touchCollections[currentTouchIndex].Id, touchCollections[currentTouchIndex].Pressure, position));
                else if (touchCollections[currentTouchIndex].State == TouchLocationState.Pressed &&
                    touchData[TouchListenerType.Press].Count > 0)
                    touchData[TouchListenerType.Press].ForEach(d => d.Invoke(touchCollections[currentTouchIndex].Id, touchCollections[currentTouchIndex].Pressure, position));
                else if (touchCollections[currentTouchIndex].State == TouchLocationState.Released &&
                    touchData[TouchListenerType.Release].Count > 0)
                    touchData[TouchListenerType.Release].ForEach(d => d.Invoke(touchCollections[currentTouchIndex].Id, touchCollections[currentTouchIndex].Pressure, position));
            }
        } catch { } //Enumeration could have been changed

If a subscriber decides to unsubscribe or to add another subscription based on the provided input, the exception System.InvalidOperationException will be thrown, because the event subscriber count has been changed. Till now I just put a try-catch around the block. But I would like to avoid the original problem.

Based on the fact that every subscriber is able to unsubscribe/subscribe in the delegate, I can't work with semaphores. Also I would like to avoid to create a copy of the event every update cycle, since this application is running on mobile devices. How am I able to solve this problem?

Upvotes: 1

Views: 111

Answers (1)

Colin Zabransky
Colin Zabransky

Reputation: 158

Perhaps a Concurrent Dictionary is sufficient?

You may also need to implement Custom Event Accessors.

Edit:

The error is generated by the List<T>.ForEach statement, where the collection is changed during iteration. A for loop should be used to allow for this.

Upvotes: 1

Related Questions