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のコメントに応えて:

親イテレータから1つの結果を返す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と呼ばないでください」と言っているのではありません。理由があります。たとえば、ファイナライズはかなり後で発生する可能性があります。ここでは、結果についてのみ説明します)。

ただし、ADオブジェクトは注目すべき例外です。特に、SearchResultCollectionこの問題に悩まされていることで知られています(参照:MSDN(クラスドキュメントと他の記事の両方)、およびActive Directory:Active Directoryの設計、展開、および実行)。技術的な理由から、ファイナライザーでリソースを解放することはできないようです。そのため、disposeを呼び出さないと、メモリリークが発生します。

ScottとJoeが指摘しているように、MSDNの例の多くは、コレクション内のアイテムの破棄を呼び出していません。ただし、元WindowsAzureテクニカルエバンジェリストであり、ディレクトリサービスプログラミングの.NET開発者ガイドの共著者であるRyan Dunnは、このブログ投稿の各項目でdisposeを呼び出すために使用することをお勧めします。投稿から:

一般に、次のオブジェクトタイプでは常にDispose()を明示的に呼び出します。

  • DirectoryEntry
  • SearchResultCollection(.FindAll()から)
  • DirectorySearcher(SearchRootを明示的に設定していない場合)

これは、「信頼できる情報源」に最も近いと思います。しかし、私の個人的な意見は次のとおりです。

  • 可能であれば、disposeを呼び出してください。特に、Joeの拡張メソッドを使用してLINQ機能を取り戻すことができれば、問題は発生しません。
  • リフレクター/ilspy/ ildasmおよび/またはdotTraceのようなメモリプロファイルを使用して、実際に何が起こっているかを確認します(基本的に、スコットはすでに行ったことですが、さらに深くなります)
于 2013-01-31T13:46:57.417 に答える
4

私はもともと同じ質問をするためにサイトに来ましたが、あなたの質問を見て、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は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 に答える