25

Resharperは、これらの変数をお勧めします。

List<string> senderDeviceIDList;
string senderDeviceID;
. . .
            foreach (var item in PlatypiIds)
            {
                senderDeviceIDList = await GetSenderDeviceIDForSenderID(item);
                senderDeviceID = senderDeviceIDList[0];

...次のように、内部スコープで宣言できます。

    foreach (var item in PlatypiIds)
    {
        List<string> senderDeviceIDList = await GetSenderDeviceIDForSenderID(item);
        string senderDeviceID = senderDeviceIDList[0];

...しかし、それは本当に「もっと良い」のでしょうか?これにより、変数がN回(foreachループごとに1回)宣言されませんか?

4

4 に答える 4

33

ちなみに、スコープの内側または外側の変数は で宣言されているため、ここではパフォーマンスやメモリ割り当ての点で利点はありませifIL

唯一の利点は、変数スコープのローカライズです。使用されているスコープに移動すると、次のような利点があります。

  • 簡単なリファクタリング (最も重要かもしれません)

  • 読みやすさ。スコープ内に変数が表示されている場合は、そのスコープ内でのみ使用されていることがわかります。明らかに内部にない変数が表示されている場合は、それを変更するとコードの他の部分に影響を与える可能性があることがわかります。したがって、それを変更すると、潜在的な危険が生じます。

要するに、それはあなたが書いているコードの読みやすさと使いやすさに関するものであり、パフォーマンスやメモリ消費の利点をもたらすものではありません.

于 2012-12-17T21:50:26.167 に答える
10

これにより、変数が N 回 (各 foreach ループに対して 1 回) 宣言されることになりませんか?

論理的には、概念的な観点からはそうです。それがポイントです! 論理的には、ループごとに 1 回存在し、ループの範囲外では意味がありません。

実装の詳細としては、いいえ、複数のローカル変数が作成されることはありません。メソッドには単一の変数しかなく、一般的な場合 (および許可されている場合) に再利用されます。匿名メソッドで変数を閉じる場合など、変数を再利用できない例外的なケースがあります。

C# では、すべてのローカル変数を使用する前にそれらを初期化する必要があるため、ランタイムは各ループ後にそれをクリアする責任さえないため、コンパイラは以前にあったガベージを再利用させないことに注意してください (明示的に初期化しない限り)。ループの開始時にデフォルト値に戻します)。

于 2012-12-17T21:50:54.673 に答える
3

とにかく、反復ごとにこれらのオブジェクトのインスタンスを割り当てています。最初のアプローチで異なるのは、2番目の例のように反復ごとにではなく、参照を1回宣言していることだけです。

foreach ループの最後でこれらのオブジェクトを最終状態 (ヘアリー) で使用する必要がある場合は、最初のアプローチを使用することをお勧めします。

于 2012-12-17T22:00:27.437 に答える
0

利益が存在する場合もあります。

結果の配列が巨大な場合、それを内側のスコープに移動する (つまり、スコープと有効期間を減らす) と、後のガベージ コレクション世代にシフトされず、ガベージ コレクションにかなりの遅延が生じる可能性があります。


[賛成票に驚いた後]私の古い答えを説明し、私の言葉から部分的にあきらめることにしました (27.10.2021)

詳細#0。
2 つのオプションは、可視性の範囲、つまり有効期間が異なります。「for」ループ内で宣言された変数は、宣言から}このループまで、つまり反復の終わりまで存続します。これは、変数が各反復の終了後、次の反復の宣言行に到達するまで存在しないことを意味します!

そして、「for」ループの外側で宣言された変数は、メソッド本体の全期間にわたって存続します(最初の例では、メソッド本体の最上位で宣言されていると想定しています)。

わかりました、それは何に影響しますか?

変数は、オブジェクトへのポインターを表す場合があります。そしてオブジェクトは、少なくとも誰かがそれらを指している場合にのみ生きます。誰もそれらを指摘しなければ、誰がそれらを参照できるでしょうか? 逆もまた同様です - 誰かがオブジェクトを指している場合、それは将来のある時点でそれを参照する可能性があるため、生きている必要があります。これがまさにガベージ コレクター (GC) のロジックです。

そのため、あるオブジェクトを指す変数の可視性スコープを離れると、GC はこのポインターの考慮を停止する可能性があります。そして、そのオブジェクトがそれ自体 (変数) へのポインターを 1 つしか持っていない場合、このオブジェクトは、誰もそれを指していないため、既に存在していません。ただし、占有されたメモリの観点からは引き続き存続します-GCが収集されるのを待つのはヒープ内のガベージです(次のガベージコレクションの実行時またはそれ以降-いつメモリを解放するかはGC次第です)。

オプションに戻ります。メソッドの実行中に、GC が許可されているか、変数が指している/指していたオブジェクトを収集しないかという点でこれらのオプションが異なるポイントがあります。ガベージ コレクションがいつでも発生する可能性がある限り、変数宣言を内部スコープに移動すると、そのオブジェクトが収集される可能性が高くなります。

Aaaaaand.. 99.9% の確率で心配する必要はありません。なぜなら、このオブジェクトは将来のある時点で収集されるからです! しかし..

詳細#1

「しかし」はありません。本当 :)

2016 年には、LOH (ラージ オブジェクト ヒープ) 内のオブジェクトにも世代があると思い込んでいたので、GC がオブジェクトを収集できるようにする速度が重要であると誤解されていました。したがって、ジェネレーション 2 オブジェクトは非常に長寿命のオブジェクトです。これは現在では当てはまりません ( docsを参照) - LOH オブジェクトは、存続期間全体にわたって第 2 世代のオブジェクトです。したがって、変数を LOH オブジェクトに急がせる必要はありません - あなたはすでに遅れています :)

これらのオブジェクトが大きくても、LOH に十分な大きさではない場合でも、この問題 (メモリ フットプリントとパフォーマンス) を調査する必要があるという証拠が見つかるまでは、おそらく心配する必要はありません。

教訓
だから、私の答えは、時々利益が存在する [しかしそれは無視できる] であるべきです。

適切なスコープを指定することは、そもそも自分自身とチームメイトにとって役立つものであり、派手なパフォーマンスのトリックではありません。

于 2016-02-19T11:41:40.763 に答える