Подтвердить что ты не робот

Does 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:

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

Да, я думаю, что это поможет работать с 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 ...)

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

4b9b3361

Ответ 1

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

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

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

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

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

Это самое близкое, что вы можете иметь к "авторитетному источнику", я полагаю; однако мое личное мнение:

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

Ответ 2

Я изначально пришел на сайт, чтобы задать тот же вопрос, но, видя, что ваш вопрос дал мне мотивацию вырваться 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 для вас на каждом члене.

Итак, да, он уничтожает все члены, а затем некоторые.