避免集合已修改错误

发布于 2024-11-15 02:39:13 字数 711 浏览 0 评论 0原文

问题:

我有以下代码:

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

显然我收到错误。

我想要做的是将 GenericListInstanceB 更改为我创建的类,该类跟踪应删除的项目。然后,当循环完成时,它会将它们全部删除。与添加项目相同。

这很好,我可以创建一个具有内部列表的类,以及要添加的项目和要删除的项目的列表。然后,另一个名为 AddRemovePendingItems 的方法实际上“更新”列表(相应地删除和添加项目)。棘手的部分是自动调用该方法。

想法:也许看看GetEnumerator何时被调用?也许用 IDisposable 做一些聪明的事情?

问题:我如何知道 for 循环何时退出并且我们已经完成对集合类的迭代,以便我可以调用我的 AddRemovePendingItems 方法?,特别是如果循环提前中断的话?

注意我想避免任何不必要的复制,因为我想消除/最小化垃圾收集,所以我不能只是迭代副本/创建新副本或类似的东西。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

十二 2024-11-22 02:39:13

您提到了 IDisposable,它提供了一种实现此目的的方法:

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 */
}

这将保证任何时候使用 foreach 枚举您的集合时,RemovePendingDeletes() 函数将在枚举器被释放时被调用。但请注意,如果您直接调用 GetEnumerator() 并忘记释放枚举器,这可能会变得很糟糕。

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.

刘备忘录 2024-11-22 02:39:13

这个怎么样。我假设 MethodThatCouldRemoveAnyItemInGenericListInstanceB 函数从列表中的任何位置删除一个项目或不删除任何项目,则不会添加任何项目。

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

危险、老式、“臭”,但是,它可以做你想做的事,而不需要有一个专门的列表或一些魔法来捕获列表的处理。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文