14

在 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 ...)

但是有必要吗?

4

2 回答 2

16

一般来说,在很多情况下,不调用 Dispose() 不会导致大问题:编写良好的一次性对象将实现与在终结器中清理事物所需的相同逻辑。(免责声明:我不是说“不要调用 dispose”:它的存在是有原因的!例如,Finalization 可能会在以后发生。我只是在此处描述后果)。

但是,AD 对象是一个明显的例外。特别SearchResultCollection是因遭受此问题而闻名(参考:MSDN(包括类文档和其他文章)和Active Directory:设计、部署和运行 Active Directory)。似乎由于技术原因无法在其终结器中释放资源,因此不调用 dispose 会导致内存泄漏。

正如 Scott 和 Joe 所指出的,许多 MSDN 示例并未对集合中的项目调用 dispose;但是,Ryan Dunn,前 Windows Azure 技术布道者和.NET 开发人员目录服务编程指南的合著者,建议对这篇博文中的每个项目使用调用 dispose 。从帖子:

通常,始终对以下对象类型显式调用 Dispose():

  • 目录条目
  • SearchResultCollection(来自 .FindAll())
  • DirectorySearcher(如果您没有明确设置 SearchRoot)

我相信这是最接近“权威来源”的地方;但是我个人的看法是:

  • 如果可以,请致电处置。不会有任何坏处,尤其是如果您可以使用 Joe 的扩展方法恢复 LINQ 功能
  • 去使用反射器/ilspy/ildasm和/或像dotTrace这样的内存配置文件来真正了解发生了什么(基本上,斯科特已经做过,但更深入)
于 2013-01-31T13:46:57.417 回答
4

我最初来到该网站是为了问同样的问题,但看到你的问题让我有动力打破ILSpy并弄清楚自己是否确实做到了。

首先是搜索结果的dispose函数:

// 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 是 a 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。

所以,是的,它确实处理了所有成员,然后处理了一些成员。

于 2012-05-23T16:21:54.587 回答