2015-12-15 12 views
6

として働いていました。これに対する解決策はここで十分に文書化されており、私はコードを見てすぐにセッション変数をstringにキャストすることが修正されていることをすでに知っていました。可能な意図しない参照比較では、私は次のようなコードを持っていることを意図し

しかし、コードは元々書かれて以来、何年も経っていません。今週までのテスト環境では、ifステートメントはtrueと評価され、//do stuffセクションが実行されました。この誤ったコードは、本番環境で意図したとおりに動作しています。

これはどのようにすることができますか?書かれているように、このコードが意図したとおりに機能するはずの理由はありません。まだ生産しています。そして、このコードを作ってはいけないはずだったのですが、突然その作業を止めました(あるいは、いつものように振る舞います)。

+0

は、テスト環境のprocからのセッションですか? –

+3

この質問では2つのことが混乱しています。まず、質問には論理的な誤りが含まれています。コードの動作は常に同じです。 2つの参照が等しいかどうか比較します。それが真実ならば、それは参照が等しいからです。それが一貫して真実を生むならば、参照は一貫して等しい。私はあなたがここで混乱していることを理解していません。第二に、私は私の人生のために、ここでヌル合体オペレータが意味するものを理解することはできません。コードは「値がnullの場合は空とNULLを比較します」という意味ですが、なぜですか? nullの場合、値はすでに "foo"ではありません! –

+0

'Session [key]'はどのくらい正確に設定されていますか?それは何と比較されますか?テスト環境と本番環境ではどの.NET Frameworkのバージョンを使用しますか? 2つの環境の間には、文字列インターンシングが異なるように動作する原因となったいくつかの違いがなければなりません。あなたが投稿したコードは2文字列のリテラルを使用します - アフリカンこれらは、インターンシップがアセンブリレベルでオフにされない限り、常にインターンンされます。 –

答えて

4

文字列リテラル「foo」がinternedです。つまり、使用されるたびに同じオブジェクトが参照されます。

共通言語ランタイムは、プログラム内でプログラムで宣言または作成された一意のリテラル文字列に対する単一の参照を含む、インテルプールと呼ばれるテーブルを維持することによって、文字列の記憶域を節約します。したがって、特定の値を持つリテラル文字列のインスタンスは、システム内に1回しか存在しません。

たとえば、複数の変数に同じリテラル文字列を割り当てると、ランタイムはインターンプールからリテラル文字列への同じ参照を取得し、それを各変数に割り当てます。

だから、object.ReferenceEquals("foo", "foo")が本当である理由です。

あなたが動的に作成された文字列と同じことを行う場合、それはインターンされず、参照は文字列のインターンがあなたが異なる動作を得ることができる理由です、実装に応じて異なる動作をすることができます

object str = new StringBuilder().Append("f").Append("oo").ToString(); // str = "foo" 
object.ReferenceEquals(str, "foo");         // false 

同じではありません参照によって文字列を比較するときに、異なる環境で実行されます。

+0

Object.Equalsチェックを使用して、「正しく」(「Object.Equals((this.Session [key] ?? string.Empty)」、「foo」) 'を実行する方法の例も含まれています。等価関数のオーバーロードのため、両方のオブジェクトが真の型でなく、nullである場合に機能します) –

+0

@ScottChamberlainこれは、コードを修正するための非常にラウンドアバウトの方法です。最も簡単な方法は 'Session [key]'を文字列にキャストし、適切な文字列比較を使うことです。 – phoog

+0

@phoog 'Session [key]'は 'string'を保持することもあれば保持しないこともあります。私は、それが常に同じタイプであることが最も良いプログラムであることに同意しますが、レガシーコードがすでに間違いをしていることが示されているので、セッション内の文字列以外のものは絶対に保存しないと信じられますか変数。 –

2

比較がうまくいったのは幸運でした!あなたの例では、文字列 "foo"はinternedです。つまり、両方の文字列リテラルが一度格納され、両方が同じ参照を持っています。しかし、2つのfooのうちの1つが別のアセンブリで定義されているか、またはデシリアライズされているか、何らかの形でコード内に構築されている場合(たとえばstring s = "f"; string t = s + "oo";)、参照は異なる場合があります。 Session[key]がオブジェクトとしてタイプされているので、参照の比較が実行されます。

if ((string)Session[key] == "foo") { ... } // This will perform a textual comparison. 

Equalsが多型であるため)あなたはまた、これを記述することができます:

合体は、しかし、鋳造があり、必要ありません

if (Session[key].Equals("foo")) { ... } // This will perform a textual comparison. 

2つの文字列値を比較することは十分ではありません文字列として比較するには、静的にはstringと入力する必要があります。

関連、このテーマに関するジョンスキートの非常に興味深い記事:https://stackoverflow.com/a/3678810/880990