Избегать сбора была изменена ошибка - PullRequest
2 голосов
/ 10 июня 2011

Проблема:

У меня есть следующий код:

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

Очевидно, я получаю ошибку.

Я хочу изменить GenericListInstanceB на класс, который я создаю, который отслеживает элементы, которые он должен удалить. Затем, когда цикл завершен, он удаляет их все. То же самое с добавлением элементов.

Это нормально, я могу создать класс с внутренним списком, списком элементов для добавления и элементами для удаления. Затем другой метод с именем AddRemovePendingItems, который фактически «обновляет» список (соответственно удаляет и добавляет элементы). Самое сложное - заставить этот метод вызываться автоматически.

Идеи: Может быть, смотреть, когда GetEnumerator вызывается? Может быть, делать что-то умное с IDisposable?

Вопрос: Как узнать, когда завершился цикл for, и мы завершили итерацию по моему классу коллекции, чтобы я мог вызвать свой метод AddRemovePendingItems?, Особенно если прерывание цикла происходит раньше? *

Примечание Я хочу избежать ненужного копирования, так как я хочу исключить / минимизировать сборку мусора, чтобы я не мог просто перебрать копию / сделать новую копию или что-то в этом роде.

Ответы [ 2 ]

3 голосов
/ 10 июня 2011

Вы упомянули 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() напрямую и забудете утилизировать перечислитель.

0 голосов
/ 10 июня 2011

Как насчет этого.Я предполагаю, что функция 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));
}

Опасный, старомодный и "вонючий", но он делает то, что вы хотитебез необходимости иметь специализированный список или некоторую магию, чтобы заманить в ловушку уничтожение списка.

...