0

次のコードを使用して、アドレス帳から電話番号を取得しています。

ABAddressBook mybook = new ABAddressBook();
ABPerson[] allPeople =  mybook.GetPeople();
foreach(ABPerson thisPerson in allPeople){


      if(thisPerson.GetPhones() != null)
             ABMultiValue<string> myMultiPhone = thisPerson.GetPhones();

      }
}

コードを try catch でラップすると、一部の時間は機能しますが、常に機能するとは限りません。すべての電話番号を問題なく取得できる場合もあれば、電話番号のランダムな取得が停止し、try catch で「電話番号の取得中にエラーが発生しました。ハンドルを null にすることはできません。パラメータ名: ハンドル」というエラーが表示される場合もあります。

4

1 に答える 1

0

そうしないでください。具体的には、そのように連続して ABPerson.GetPhones() を呼び出さないでください。はABMultiView<string>ネイティブ リソースをラップします (これがABMultiValue<T>がIDisposableを実装する理由です。

より良い方法は次のとおりです。

var mybook = new ABAddressBook();
foreach (var person in mybook.GetPeople()) {
    using (var phones = person.GetPhones()) {
        if (phones != null) {
            // do something with phones...
        }
    }
}

これにより、後でリソースをクリーンアップするために GC に依存することなく、リソースが確実にクリーンアップされます。

ただし、コード サンプルがクラッシュする理由がわかりません。ファイナライザーの実行は別のスレッドで実行されるため、この方法で多くの「ガベージ」オブジェクトを作成しているため (ABMultiValue<string>各人に 2 つのインスタンスを作成)、GC がそれらのいくつかをガベージとしてマークし、ファイナライザーが次に、デストラクタが実行されます...これはネイティブコードを呼び出してリソースをクリーンアップします...しかし、ネイティブライブラリはここでスレッドセーフではない可能性があります. 推測です。

于 2010-02-25T16:00:51.347 に答える