PrincipalSearchResult <T>是否自动处理其集合中的所有元素?

Joe*_*Joe 13 .net directoryservices principalsearcher

在MSDN文档中找不到任何关于此的内容.

也就是这样做,说:

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

这是我见过的大多数例子,或者我应该这样做:

using(PrincipalSearcher searcher = ...)
{
    foreach(var principal in searcher.FindAll())
    {
        using (principal)
        {
            // ... do something ...
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)

后者(在迭代期间明确地处理每个项目)看起来"更安全" - 即符合指南以明确处理所有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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

可以用作:

searcher.FindAll().EnumerateAndDispose().Select(... use LINQ ...)
Run Code Online (Sandbox Code Playgroud)

但这有必要吗?

Lor*_*tté 15

通常情况下,在许多情况下,不调用Dispose()不会导致大问题:写得好的一次性对象将实现在终结器中清理所需的相同逻辑.(免责声明:我不是说"不要召唤处理":这是有原因的!例如,终结可能会发生很多次.我只是描述了这里的后果).

但是,AD对象是一个值得注意的例外; 特别是,SearchResultCollection因为遇到这个问题而闻名(参考文献:MSDN(包括类文档和其他文章),以及Active Directory:设计,部署和运行Active Directory).似乎由于技术原因,无法在其终结器中释放资源,因此不调用dispose将导致内存泄漏.

正如Scott和Joe所指出的,许多MSDN示例都没有对集合中的项目进行dispose调用; 但是,前Windows Azure技术布道者Ryan Dunn是"目录服务编程.NET开发人员指南"的共同作者,他建议使用此博客文章中的每个项目调用dispose .从帖子:

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

  • 的DirectoryEntry
  • SearchResultCollection(来自.FindAll())
  • DirectorySearcher(如果您尚未明确设置SearchRoot)

我相信这是你对"权威来源"最接近的; 我的个人意见是:

  • 如果可以,请拨打电话.它不会有任何不好,特别是如果你可以使用Joe的扩展方法获得LINQ功能
  • 去使用reflector/ilspy/ildasm和/或像dotTrace这样的内存配置文件来真正看到发生了什么(基本上,Scott已经做了什么,但更深入)


Sco*_*ain 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

从那里我检查了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();
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以看到 foreach 循环遍历它拥有的所有成员。所以它正在为每个成员执行 Dispose。

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

  • 感谢你的回答。我也查看了实现,但得出的结论与你不同。(1)ResultSet是抽象的,所以每个具体实现都需要检查;(2) 从上面我可以看到 ADDNLinkedAttrSet 可能正在处理它当前拥有的项目,但我不确定已经返回给调用者的项目;(3) 我希望查看记录的行为(即,PrincipalSearcher 实现的合同的一部分),而不是依赖于我对内部实现细节的解释。 (5认同)