0

以下のコードはasp.netからのものです。


私が以下の(不十分に書かれた)コードを持っている場合

AmazonS3 s3Client = Amazon.AWSClientFactory.CreateAmazonS3Client();

// ...
// details elided
// ...

BackgroundWorker worker = new BackgroundWorker();

worker.DoWork += new DoWorkEventHandler((s, args) =>
{
    s3Client.PutObject(titledRequest);
});

new Thread(() => worker.RunWorkerAsync()).Start();

s3Clientガベージコレクターは、バックグラウンドワーカーがオブジェクトを処理するまで、オブジェクトを収集することは決してないほど賢いのでしょうか。


バックグラウンドワーカーを直接起動したときに発生するasp.net内で発生する厄介なエラーを修正するためにのみ、スレッド内でバックグラウンドワーカーをキックオフしていることに注意してください。

4

2 に答える 2

5

はい、そうなります。コンパイラは、クロージャで参照する各ローカルのフィールドを含む新しいクラスを生成します。クロージャー本体はそのクラスのメソッドに発行され、それを含む関数のすべてのローカルは、そのクロージャー オブジェクトのフィールドを参照するようにコンパイラーによって書き換えられます。

この魔法はすべてコンパイル時に発生します。ランタイムはそれについて何も知る必要はありません。ランタイムは、デリゲートのターゲットであるオブジェクトを収集しないほど十分にスマートであるため、クロージャーによって参照されるローカルの有効期間は、結果のデリゲート オブジェクトの有効期間まで延長されることが保証されます。

説明のために、コンパイラは次のようなものを吐き出します。

[System.Runtime.CompilerServices.CompilerGeneratedAttribute]
internal class ClosureImplementation // See note 1
{
    public AmazonS3 s3Client;

    public void Method(object s, EventArgs args)
    {
        s3Client.PutObject(titledRequest); // See note 2
    }
}

次に、メソッドで、これが代わりに発行されます。

ClosureImplementation closure = new ClosureImplementation();
closure.s3Client = Amazon.AWSClientFactory.CreateAmazonS3Client();

// ...

worker.DoWork += closure.Method;

ノート:

  1. 生成されたクラスの名前はコンパイラによって選択されます。ClosureImplementationはほんの一例です。
  2. どこtitledRequestから来たのかを知るのに十分なコンテキストがないため、コンパイラがそれを処理する方法について意図的に説明しませんでした。
于 2012-11-19T19:23:27.700 に答える
3

要するに、はい。

イベント ハンドラーにラムダを使用しており、ローカル変数を閉じています。これは、ラムダが定義されているブロックの外側のスコープから変数を使用していることを意味します。これは、ラムダがコンパイラによって「実際の」メソッド (クラス内で、実際の名前とオブジェクト インスタンスとすべて) には、そのクラスのフィールドとして閉じたローカル変数への参照が含まれます。これにより、ラムダがどこでも参照されなくなり、どこでも実行されなくなるまで、そのオブジェクトがスコープ内に保持されます。

于 2012-11-19T19:25:31.997 に答える