2011-06-24 4 views
21

次(重く編集され、擬似)コードを考える:なぜresharperは変更されたクロージャの警告にアクセスするために "変数を配列でラップする"ことを提案しますか?

int count = 0; 
thing.Stub(m => m.AddBlah()).WhenCalled(o => count++); 
thing.Stub(m => m.RemoveBlah()).WhenCalled(o => count--); 

DoStuff(thing); 

Assert.AreEqual(1, count); 

ReSharperのはカウントに警告を提供 - 「修飾閉鎖へのアクセスを」。私はなぜこの警告が出るのか理解しています(カウント変数は2つの異なるラムダで修正されており、望ましくないセマンティクスを持つ可能性があります)が、私はReSharperの助言を理解していません。私がReSharperにこれをさせるならば、私は得る:

int count[] = { 0 }; 
thing.Stub(m => m.AddBlah()).WhenCalled(o => count[0]++); 
thing.Stub(m => m.RemoveBlah()).WhenCalled(o => count[0]--); 

DoStuff(thing); 

Assert.AreEqual(1, count[0]); 

警告なし。

アレイを安全に使用するのはなぜですか?

+0

どのバージョンのReSharperがこれに見えましたか? –

答えて

2

これは2種類が異なるためです。 int型はValue型で、配列は参照型です。これは、intがスタック上にあり、配列のポインタがスタック上にあることを意味します。

値タイプを更新すると、そのスタックメモリが更新されます。一方、参照型は、スタックメモリだけを残して、それが指しているものを変更します。

Resharperは2つの異なるラムダメソッドが値を更新する場所を指すメモリの周りにクロージャを作成しているため、配列について文句を言いません。両方のLambdasは同じアドレスを取得し、元のアドレスを変更しません。

+1

しかし、int変数の周りを閉じているラムダも、どちらもメモリ内の同じポイントを指しているので、違いは何ですか?コードはどちらの場合も同じように実行されるため、実装は賢明ですが、違いはありません。しかし、私はresharperが彼らを別々に扱う理由を見ません。 – citizenmatt

+0

@citizenmatt、メソッドが返ってきたときのことを考えて、ReSharperはDoStuff(物)への呼び出し中にlambdaが実行されるだけであることを知らない –

+0

これは正しい理由ではありません。ラムダ内に参照変数または値変数を取り込むことに違いはないため、どちらの動作も同じです。 http://stackoverflow.com/questions/5438307/detailed-explanation-of-variable-capture-in-closures –

12

私はReSharperでこれと同じことを気づきましたが、なぜ値が配列にラップされたときに警告しないのか不思議に思っていました。ここでの他の答えは残念ながら間違っていて、クロージャがどのように実装されているのか誤解しているようですので、私はこのリファクタリングの背後にある根拠を説明しようと考えました。

あなたが見てきたように、結果は配列ラップされているかどうかにかかわらず同じなので、リファクタリングは実際には何も修正せず、適用後に通常の修正クロージャにアクセスする際に遭遇する可能性のある問題変化。ただし、countアレイ自体が変更されていない(変更されていない)ため、「変更されたクロージャへのアクセス」警告はもはや意味をなさない。

変更は実際には(少なくとも私の意見では)明らかになったわけではないので、この提案は本質的にはReSharperに問題を無視するように指示しているようです。// ReSharper disable AccessToModifiedClosureエラーを抑制するメカニズム。

+0

私はこのコードの他の理由を考えることができないので、これは彼らの論理的根拠であると思われます"実際に実装しているのであれば、1要素配列の変数へのすべてのアクセスをラッピングすることは、警告を単に使用するときだけコメントを無効にするよりも面倒ではないと思うのは奇妙に思えます。 – jam40jeff

関連する問題