Найди ошибку: плохие сравнения. Часть 3
Вы обратили внимание на то, что сравнение длины строк в предыдущем примере было слишком длинным? Его можно переписать следующим образом:
static int ByLength(string x, string y)
{
if (x == null && y == null) return 0:
if (x == null) return -1;
if (y == null) return 1;
return CompareInts(x.Length, y.Length);
}
static int CompareInts(int x, int y)
{
// Получаем положительное значение, если x больше, отрицательное – если y больше, нуль, если они равны
return x - y;
}
static Comparison<T> ThenBy<T>(this Comparison<T> firstBy, Comparison<T> thenBy)
{
return (x,y)=>
{
int result = firstBy(x, y);
return result != 0 ? result : thenBy(x, y);
}
}
Гораздо лучше! Мой метод сравнения длин строк значительно упростился, я легко могу объединять сравнения с помощью метода расширения ThenBy и я могу повторно использовать метод CompareInts в качестве вспомогательной функции в других функциях сравнения.
Где здесь ошибка?
.
.
.
.
.
.
После прошлого раза, найти разгадку будет просто. Длины строк всегда положительны и на практике никогда не превосходят нескольких миллионов; CLR не позволяет создавать огромные многогигабайтные строки. Функция CompareInts безопасна при сравнении длин строк, однако в общем случае, она небезопасна. В частности, при сравнении Int32.MinValue и Int32.MaxValue, разница равна 1. Очевидно, что минимальное целое меньше максимального целого, однако этот метод возвращает противоположный результат! Метод CompareInts должен быть таким:
static int CompareInts(int x, int y)
{
if (x > y) return 1;
if (x < y) return -1;
return 0;
}
Мораль этой истории такова: функция сравнения, которая не выполняет сравнения, скорее всего неверная.
Вычитание не является сравнением.