为什么VS 2017生成没有未经检查的块的GetHashCode

时间:2019-02-15 15:40:27

标签: c# visual-studio visual-studio-2017 gethashcode

我最近发现Visual Studio 2017可以自动生成https://laraveldaily.com/multiple-database-connections-in-the-same-laravel-project/Equals的替代,但是我想知道为什么GetHashCode实现不在unchecked块中?

我用两个公共字符串属性Foo和Bar创建了一个简单的类,生成的GetHashCode实现如下所示。

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; } 实现的未经检查的实现很重要,因为它很可能会溢出,并且我们不希望有任何溢出异常,因为它可以环绕起来很好。

2 个答案:

答案 0 :(得分:2)

默认情况下,C#项目不会检查上溢和下溢。

右键单击项目,选择Properties,在底部的Build选项卡上选择Advanced...,选中标记为Check for arithmetic overflow/underflow的框

现在,默认行为是,如果显式System.OverflowException块中没有溢出,则抛出unchecked

如果您在为项目启用了溢出检查的情况下自动生成EqualsGetHashCode的替代项,则未检查的块将按预期存在

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;
    }
}

答案 1 :(得分:1)

很明显,我对无检查与未检查与已检查的理解存在缺陷。编写一些简单的测试很简单,以查看此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);
    }
}