Почему VS 2017 генерирует GetHashCode без непроверенного блока - PullRequest
0 голосов
/ 15 февраля 2019

Я недавно обнаружил, что Visual Studio 2017 может автоматически генерировать переопределения для Equals и GetHashCode, но мне было интересно, почему реализация GetHashCode не находится в блоке unchecked ?

Я создал простой класс с двумя общедоступными строковыми свойствами Foo и Bar, и сгенерированная реализация GetHashCode показана ниже.

public override int GetHashCode()
{
    var hashCode = -504981047;
    hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Foo);
    hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Bar);
    return hashCode;
}

Мне показалось, что контрольная реализация GetHashCode не проверенаважно, потому что очень вероятно, что он переполнится, и мы не хотим никаких исключений переполнения, потому что это хорошо, если это обернется.

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

По умолчанию проекты C # не проверяют наличие переполнения и недостаточного заполнения.

Щелкните правой кнопкой мыши проект, выберите Properties, На вкладке Build внизу выберите Advanced..., установите флажок с надписьюCheck for arithmetic overflow/underflow

Теперь по умолчанию выбрасывается System.OverflowException, если когда-либо возникает переполнение не в явном блоке unchecked.

Если вы автоматически генерируете переопределения для Equalsи GetHashCode с включенной проверкой переполнения для проекта, тогда непроверенный блок находится там, как и ожидалось

public override int GetHashCode()
{
    unchecked
    {
        var hashCode = -504981047;
        hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Foo);
        hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Bar);
        return hashCode;
    }
}
0 голосов
/ 15 февраля 2019

Очевидно, что мое понимание отсутствия проверок и проверок и проверок было ошибочным.Было достаточно просто написать несколько простых тестов, чтобы увидеть поведение переполнения в этом fiddle .

Краткое резюме таково:

Если выполняется без явных проверок

  • Если компилятор может легко и статически определить, что код будет переполнен, произойдет ошибка компиляции.
  • Если во время выполнения произойдет переполнение, будет не будут какие-либо исключения из-за переполнения.

Если выполняется явно не проверено

  • Компилятор разрешит код, который, очевидно, будет переполнен
  • Никаких исключений переполнения во время выполнения не будет выдано

При запуске явно проверено

  • Если компилятор может легко и статически определить, что код будет переполнен, будет ошибка компиляции.
  • Если во время выполнения будет переполнение, будет выдано System.OverflowException.

Итак ... Я думаю, урок из всего этогоесли у вас есть некоторые расчеты, которые могут закончитьсяпоток, и вы заботитесь о переполнении, очень важно поместить это внутри блока checked.Если у вас есть код, который может переполниться, и вы не заботитесь о переполнении, очевидно, вы можете пропустить непроверенный блок (если ваш код явно не переполнится с точки зрения статического анализа).

Код изСкрипка здесь также скопирована для потомков.

using System;

public class Program
{
    public static void Main()
    {
        var rand = new Random();
        int test = 0;

        //obscured enough that the compiler doesn't "know" that the line will produce an overflow
        //Does not run explicitly as checked, so no runtime OverflowException is thrown
        test = rand.Next(Int32.MaxValue-2, Int32.MaxValue) + 10;

        //simple enough that the compiler "knows" that the line will produce an overflow
        //Compilation error (line 16, col 10): The operation overflows at compile time in checked mode
        //test = Int32.MaxValue + 1;

        //Explicitly running as unchecked. Compiler allows line that is "known" to overflow.
        unchecked
        {
            test = Int32.MaxValue + 1;
        }

        Console.WriteLine(test);

        //Explicitly running as unchecked. Still no runtime OverflowException
        unchecked
        {
            test = test - 10;   
        }

        Console.WriteLine(test);

        //Explicitly running as checked. System.OverflowException: Arithmetic operation resulted in an overflow.
        checked
        {
            test = test + 10;
        }

        Console.WriteLine(test);
    }
}
...