今日、いくつかのコードをリファクタリングしているときに、非常に奇妙な動作に遭遇しました。
次のようなコードがいくつかありました。
private AType Blah
{
get
{
return (from something in AList
where _x == null || something.x == _x
where _y == null || something.y == _y
where _z == null || something.z.IsSameAs(_z)
select something).Single();
}
}
型名と変数名は質問にとって重要ではないため、匿名化しました。
_x と something.x の型は文字列で、_y と something.y は参照型でした。同様に _z と something.z は、値比較を伴う参照型でした。
私はこのようなことができると思いました:
public AType Blah
{
get { return AList.Single(something => DetailsMatch(something.x, something.y, something.z)); }
}
private bool DetailsMatch(string x, AnotherType y, AFurtherType z)
{
return NullOrCheck(_x, x) &&
NullOrCheck(_y, y) &&
NullOrCheck(_z, z.IsSameAs);
}
private bool NullOrCheck<T>(T value, T expected) where T : class
{
return NullOrCheck(value, v => v == expected);
}
private static bool NullOrCheck<T>(T value, Func<T,bool> check) where T : class
{
return value == null || check(value);
}
これはすべて理にかなっているように見えましたが、驚いたことに、いくつかのテストが失敗し始めました。== 演算子を使用すると、同一の文字列 (例では "1A04" と "1A04") が等しいと見なされなくなったことが判明しました。
以下を見たCan't operator == be applied to generic types in C#? 通常の方法ではなく、文字列が参照の等価性で比較されている可能性があります。
c#でこれを行う安全な方法はありますか、またはジェネリックメソッドで == を使用することは上記の理由で危険と見なされるべきですか?
これが問題であることを確認するために、私の修正は、問題のあるメソッドを文字列ケースにインライン化することで構成され、結果として次のようになりました。
private bool DetailsMatch(string x, AnotherType y, AFurtherType z)
{
return (_x == null || _x == x) &&
NullOrCheck(_y, y) &&
NullOrCheck(_z, z.IsSameAs);
}
ちょっとプレスト-すべてが機能し、テストは再びパスします