IComparerを用いたリストのソート

IComparerを継承した独自クラスのインスタンスをリスト等で複数保持している状況下で、例えば、日付順にソートをしたい場合、以下の点に注意。

よくある手法(IComparer継承クラス内の記述)
//日時比較処理
public int Compare ( object x, object y )
{
TimeSpan ts = ( (UpdateHistory)x ).Date - ( (UpdateHistory)y ).Date;
return Convert.ToInt32( ts.TotalSeconds );
}

これだと、TotalSecondsで比較を行っている分には良いが、より厳密なTotalMiliSecondsで比較しだすと、オーバーフローを起こす。IComparerはint型のみの設定でLongが扱えないためである。
しかし、そもそもIComparerがintで必要十分なのは、以下のようになっているから。

  • 同値の場合、0を返す
  • y>xの場合、Integerの範囲で0より小さい値を返す
  • x>yの場合、Integerの範囲で0より大きい値を返す

要するに、差分値を直接returnしているのは、横着した表記をしているだけなのだ。int範囲内であれば、有効だし、文句も無いが、厳密な日付比較によるソート等では、正しくは以下のように書くべき。

//日時比較処理
public int Compare ( object x, object y )
{
TimeSpan ts = ( (UpdateHistory)x ).Date - ( (UpdateHistory)y ).Date;
long longTs = Convert.ToInt64(ts.TotalMilliseconds);
if (longTs > 0)
{
return 1;
}
else if (longTs < 0)
{
return -1;
}
else
{
return 0;
}

MSDN:IComparer
http://msdn.microsoft.com/ja-jp/library/system.collections.icomparer.compare(VS.80).aspx

なんて事は無いが、一応メモ。