Располагает ли PrincipalSearchResult<T> автоматически все элементы в своей коллекции?

Ничего не могу найти в документации MSDN по этому вопросу.

Т.е. этого достаточно, сказать:

using(PrincipalSearcher searcher = ...)
{
    foreach (var principal in searcher.FindAll())
    {
        ... do something ...
    } // The PrincipalSearchResult<T> returned by searcher.FindAll is disposed here
}

что делает большинство примеров, которые я видел, или я должен делать:

using(PrincipalSearcher searcher = ...)
{
    foreach(var principal in searcher.FindAll())
    {
        using (principal)
        {
            // ... do something ...
        }
    } 
}

Последний (явное удаление каждого элемента во время итерации) выглядит "более безопасным" - то есть соответствует директиве по явному удалению всех IDisposable объектов - но это немного грязно; например, это исключает использование LINQ для перебора результатов поиска.

В ответ на комментарий @Rup:

Вы могли бы написать итератор yield, который возвратил один результат из родительского итератора

Да, я думаю, что это будет работать, чтобы включить LINQ. Что-то вроде следующего метода расширения:

public static IEnumerable<T> EnumerateAndDispose<T>(this IEnumerable<T> collection) where T : IDisposable
{
    foreach (T item in collection)
    {
        using (item)
        {
            yield return item;
        }
    }
}

который можно использовать как:

searcher.FindAll().EnumerateAndDispose().Select(... use LINQ ...)

Но нужно ли это?

2 ответа

Вообще говоря, во многих случаях отказ от вызова Dispose() не вызовет больших проблем: хорошо написанные одноразовые объекты будут реализовывать ту же логику, которая необходима для очистки вещей в финализаторе. (Отказ от ответственности: я не говорю "не звоните распоряжаться": это происходит по причине! Например, Завершение может произойти намного позже. Я только описываю, каковы последствия здесь).

Однако объекты AD являются заметным исключением; особенно, SearchResultCollection известен тем, что страдает от этой проблемы (ссылки: MSDN (как документация по классу и другие статьи), так и Active Directory: проектирование, развертывание и запуск Active Directory). Кажется, что по техническим причинам невозможно освободить ресурсы в его финализаторе, поэтому отсутствие вызова dispose приведет к утечкам памяти.

Как отмечают Скотт и Джо, многие примеры MSDN не вызывают dispose для элементов в коллекции; однако Райан Данн, бывший технический евангелист Windows Azure и соавтор Руководства для разработчиков.NET по программированию служб каталогов, рекомендует использовать функцию dispose для каждого элемента в этом сообщении в блоге. Из поста:

В общем, всегда явно вызывайте Dispose() для следующих типов объектов:

  • DirectoryEntry
  • SearchResultCollection (из.FindAll ())
  • DirectorySearcher (если вы явно не установили SearchRoot)

Я думаю, это самое близкое к "авторитетному источнику"; однако мое личное мнение таково:

  • если можете, позвоните утилизировать. Это не сделает ничего плохого, особенно если вы можете вернуть функциональность LINQ с помощью метода расширения Джо.
  • иди и используй отражатель /ilspy/ildasm И / ИЛИ профиль памяти, такой как dotTrace, чтобы реально увидеть, что происходит (в основном то, что Скотт уже сделал, но углубляется)

Первоначально я пришел на сайт, чтобы задать тот же вопрос, но видение вашего вопроса дало мне мотивацию разжечь ILSpy и выяснить, стоит ли это делать.

Первый Функция удаления результатов поиска:

// System.DirectoryServices.AccountManagement.PrincipalSearchResult<T>
public void Dispose()
{
    if (!this.disposed)
    {
        if (this.resultSet != null)
        {
            lock (this.resultSet)
            {
                this.resultSet.Dispose();
            }
        }
        this.disposed = true;
    }
}

Оттуда я проверил resultSet.Dispose() (в моем случае resultSet был ADDNLinkedAttrSet)

// System.DirectoryServices.AccountManagement.ADDNLinkedAttrSet
public override void Dispose()
{
    try
    {
        if (!this.disposed)
        {
            if (this.primaryGroupMembersSearcher != null)
            {
                this.primaryGroupMembersSearcher.Dispose();
            }
            if (this.queryMembersResults != null)
            {
                this.queryMembersResults.Dispose();
            }
            if (this.currentMembersSearcher != null)
            {
                this.currentMembersSearcher.Dispose();
            }
            if (this.memberSearchResults != null)
            {
                this.memberSearchResults.Dispose();
            }
            if (this.memberSearchersQueue != null)
            {
                foreach (DirectorySearcher directorySearcher in this.memberSearchersQueue)
                {
                    directorySearcher.Dispose();
                }
                this.memberSearchersQueue.Clear();
            }
            IDisposable disposable = this.members as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
            IDisposable disposable2 = this.membersEnum as IDisposable;
            if (disposable2 != null)
            {
                disposable2.Dispose();
            }
            if (this.membersQueue != null)
            {
                foreach (IEnumerable enumerable in this.membersQueue)
                {
                    IDisposable disposable3 = enumerable as IDisposable;
                    if (disposable3 != null)
                    {
                        disposable3.Dispose();
                    }
                }
            }
            if (this.foreignGroups != null)
            {
                foreach (GroupPrincipal groupPrincipal in this.foreignGroups)
                {
                    groupPrincipal.Dispose();
                }
            }
            this.disposed = true;
        }
    }
    finally
    {
        base.Dispose();
    }
}

Вы можете видеть циклы foreach, где он проходит по всем имеющимся элементам. Так что это делает Dispose для вас на каждом члене.

Так что, да, он располагает всеми членами, а затем и некоторыми.

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