2012-04-22 4 views
2

メソッド内のローカル変数にパラメータ値を代入する理由はありますか?を変更せずに使用する?私。パラメータ値を直接使用するのではなく、ローカル変数に割り当てる必要がありますか?

private void MyMethod(string path) 
{ 
    string myPath = path; 
    StreamReader mystream = new StreamReader(myPath); 
    ... 
} 

するか、私はいつもこのようにそれを置くことができます(上記のコードが冗長だけではないきれいです):次のように

private void MyMethod(string path) 
{ 
    StreamReader mystream = new StreamReader(path); 
    ... 
} 

私はそれは両方の方法を動作します知っているが、私は思います私が私の理解に欠けていたことがないことを確認したい。

+1

変数が他の場所で使用されないと仮定すると、私が見ることができる最初のケースの唯一の理由はデバッグを支援することです。 – ChrisF

答えて

3

これはまったく同じことですが、唯一の違いは、最初のケースでは参照のコピーを作成することです(実行が終了したときにメソッドがスコープから外れると破棄されます)。

読みやすくするために、2番目のケースに貼り付けてください。

+0

これは必ずしも最良のケースではないことに注意してください。場合によっては、変数の使用方法に応じて問題が発生する可能性があります。詳細は以下の私の答えを見てください。 – tsells

1

私は第2の選択肢を好みます。パラメータで新しい変数を作成するのは意味がありません。また、読書の観点からは、 "myPath"変数をインスタンス化するのではなく、パス(受け取ったパス)からストリームを作成する方が理にかなっています。

4

これを行う必要があるのは(ローカルに割り当てる)唯一の時間は、foreachループまたはLinqを使用している場合です。そうしないと、変更されたクロージャの問題が発生します。

MSDNブログのスニペットです(以下の内容はすべてリンクからのものです)。

http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

しかし、私は先に自分の取得しています。この断片の出力は?

var values = new List<int>() { 100, 110, 120 }; 
var funcs = new List<Func<int>>(); 
foreach(var v in values) 
    funcs.Add(()=>v); 
foreach(var f in funcs) 
    Console.WriteLine(f()); 

ほとんどの人は100/110/120と予想しています。実際には120/120/120です。なぜですか?

()=> vは、「代理人の作成時に戻った値を返す」ではなく、「変数vの現在の値を返す」ことを意味するためです。クロージャーは、値を超えてではなく、変数を閉じます。メソッドが実行されるとき、vに割り当てられた最後の値は120だったので、それでもその値を持ちます。

これは非常に混乱しています。コードを書き込む正しい方法は次のとおりです。

foreach(var v in values) 
{ 
    var v2 = v; 
    funcs.Add(()=>v2); 
} 

ここで何が起こりますか?ループ本体を再起動するたびに、新しい変数v2を論理的に作成します。各クロージャは別のv2で閉じられます。これは1回のみ割り当てられます。したがって、常に正しい値が保持されます。

我々は拡張が

try 
{ 
    while(e.MoveNext()) 
    { 
    int m; // INSIDE 
    m = (int)(int)e.Current; 
    funcs.Add(()=>m); 
    } 

た予想通り、コードが振る舞うだろうと指定した場合は、foreachループが

{ 
    IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator(); 
    try 
    { 
     int m; // OUTSIDE THE ACTUAL LOOP 
     while(e.MoveNext()) 
     { 
     m = (int)(int)e.Current; 
     funcs.Add(()=>m); 
     } 
    } 
    finally 
    { 
     if (e != null) ((IDisposable)e).Dispose(); 
    } 
    } 

ためのシンタックスシュガーであることを指定するために基本的には、問題が発生します。

関連する問題