为什么 VS 2017 生成没有未检查块的 GetHashCode
Why does VS 2017 generate GetHashCode without an unchecked block
我最近发现 Visual Studio 2017 可以为 Equals
和 GetHashCode
自动生成覆盖,但我想知道为什么 GetHashCode
实现不在 unchecked块?
我用两个 public 字符串属性 Foo 和 Bar 做了一个简单的 class,生成的 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
实现很重要,因为它很可能会溢出,我们不希望出现任何溢出异常,因为如果它回绕就没问题。
显然我对不检查、未检查和检查的理解是有缺陷的。编写一些简单的测试来查看此 fiddle.
中的溢出行为就足够简单了
快速总结是这样的:
如果运行没有显式检查
- 如果编译器可以轻松地静态地确定代码会溢出,就会出现编译错误。
- 如果在运行时发生溢出,将不会抛出任何溢出异常。
如果运行明确取消选中
- 编译器将允许明显溢出的代码
- 不会抛出运行时溢出异常
如果运行明确勾选
- 如果编译器可以轻松地静态地确定代码会溢出,就会出现编译错误。
- 如果在运行时发生溢出,将抛出
System.OverflowException
。
所以...我想从所有这一切中得到的教训是,如果您有一些可能溢出的计算,并且您关心溢出,那么将其放在 checked
块中非常重要。如果你有可能溢出的代码,而且你不关心溢出,显然你可以跳过未检查的块(除非你的代码从静态分析的角度来看显然会溢出)。
fiddle 中的代码也复制到此处以供后代使用。
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);
}
}
默认情况下,C# 项目不检查上溢和下溢。
右键单击项目,Select Properties
,在底部的 Build
选项卡上 select 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;
}
}
我最近发现 Visual Studio 2017 可以为 Equals
和 GetHashCode
自动生成覆盖,但我想知道为什么 GetHashCode
实现不在 unchecked块?
我用两个 public 字符串属性 Foo 和 Bar 做了一个简单的 class,生成的 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
实现很重要,因为它很可能会溢出,我们不希望出现任何溢出异常,因为如果它回绕就没问题。
显然我对不检查、未检查和检查的理解是有缺陷的。编写一些简单的测试来查看此 fiddle.
中的溢出行为就足够简单了快速总结是这样的:
如果运行没有显式检查
- 如果编译器可以轻松地静态地确定代码会溢出,就会出现编译错误。
- 如果在运行时发生溢出,将不会抛出任何溢出异常。
如果运行明确取消选中
- 编译器将允许明显溢出的代码
- 不会抛出运行时溢出异常
如果运行明确勾选
- 如果编译器可以轻松地静态地确定代码会溢出,就会出现编译错误。
- 如果在运行时发生溢出,将抛出
System.OverflowException
。
所以...我想从所有这一切中得到的教训是,如果您有一些可能溢出的计算,并且您关心溢出,那么将其放在 checked
块中非常重要。如果你有可能溢出的代码,而且你不关心溢出,显然你可以跳过未检查的块(除非你的代码从静态分析的角度来看显然会溢出)。
fiddle 中的代码也复制到此处以供后代使用。
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);
}
}
默认情况下,C# 项目不检查上溢和下溢。
右键单击项目,Select Properties
,在底部的 Build
选项卡上 select 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;
}
}