Avoid Collection has been modified error

别来无恙 提交于 2020-01-15 07:15:23

问题


Issue:

I have the following code:

foreach(var ItemA in GenericListInstanceB)
{
    ItemA.MethodThatCouldRemoveAnyItemInGenericListInstanceB();
}

Obviously i get an error.

What i want to do is change GenericListInstanceB to a class i create, that keeps track of items it should remove. Then, when the loop is finished, it removes them all. Same with adding items.

This is fine, i can create a class that has an internal list, and a list of items to add and items to remove. Then another method called AddRemovePendingItems that actually 'updates' the list (removes and adds items accordingly). The tricky part is getting that method to be called automatically.

Ideas: Maybe looking at when GetEnumerator is called? Maybe doing something clever with IDisposable?

Question: How do i know when the for loop exits and we've finished iterating over my collection class so i can call my AddRemovePendingItems method?, particularly if the loop break's early?

Note I want to avoid any unnecessary copying as i want to eliminate/minimise garbage collection so i can't just iterate over a copy/make a new copy or anything like that.


回答1:


You mentioned IDisposable, which offers one way you could implement this:

public class GenericList<T> : IList<T>
{
    private class CleanupEnumerator<T> : IEnumerator<T>
    {
        private readonly GenericList<T> source;

        public CleanupEnumerator<T>(GenericList<T> source)
        {
            this.source = source;
        }

        public void Dispose()
        {
            source.RemovePendingDeletes();
        }

        /* Other IEnumerator methods here */
    }

    public IEnumerator<T> GetEnumerator()
    {
        return new CleanupEnumerator(this);
    }

    /* Other IList methods here */
}

This will guarantee that any time your collection is enumerated using foreach, the RemovePendingDeletes() function will get called when the enumerator is disposed. Be warned, however, that this could get ugly if you ever call GetEnumerator() directly and forget to dispose the enumerator.




回答2:


How about this. I'm assuming the MethodThatCouldRemoveAnyItemInGenericListInstanceB function removes one or no items from anywhere in the list, no items will be added.

bool finished = false;
int i = 0;
while (!finished)
{
    var itemA = genericListInstanceB[i];
    itemA.MethodThatCouldRemoveAnyItemInGenericListInstanceB();
    if (genericListInstanceB[i] == itemA)
        i++;
        // All other outcomes result in us leaving i alone
    finished = (i > (genericListInstanceB.Count - 1));
}

Dangerous, old fashioned and "smelly" but, it does what you want without having to have a specialised list or some magic to trap the disposal of the list.



来源:https://stackoverflow.com/questions/6305228/avoid-collection-has-been-modified-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!