为什么集合的评估顺序与使用条件运算符的其他类型的评估顺序不同

psu*_*003 7 c# visual-studio-2010 operator-precedence

尝试实现一个GetHashCode覆盖类似于Jon的Skeet的建议,在什么是覆盖System.Object.GetHashCode的最佳算法?我注意到在评估顺序中有一些奇怪的行为,当使用条件运算符对类中的集合属性进行空检查时,会导致语法错误.

考虑以下:

public class Foo
{

    public String Name { get; private set; }
    public List<String> Bar { get; private set; }

    public override Int32 GetHashCode()
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + this.Name == null ? 0 : this.Name.GetHashCode();
            hash = hash * 23 + this.Bar == null ? 0 : this.Bar.GetHashCode();
            return hash;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当您收到语法错误时hash = hash * 23 + this.Bar == null ? 0 : this.Bar.GetHashCode();,此代码将无法编译,特别是指向hash * 23 + this.Bar段.

错误是

运算符'+'不能应用于'int'和'System.Collections.Generic.List'类型的操作数

你没有得到相同的错误,hash = hash * 23 + this.Name == null ? 0 : this.Name.GetHashCode();虽然唯一的区别Name是a stringBar是a List<>.

将整个条件操作包装在一组括号中会删除错误,但这仍然无法解释为什么集合属性的处理方式与字符串属性不同.

是否有一个原因我不知道这导致对不同类型的操作进行不同的评估?

小智 7

区别在于它hash * 23 + this.Name == null是一个有效的表达式,而hash * 23 + this.Bar == null不是.+用于算术和字符串连接,但不用于向列表中添加元素.在这两种情况下,整个hash * 23 + this.... == null都被视为?:操作员的条件.


das*_*ght 5

看看这个功能:

void Crash() {
    int hash = 123;
    int crash = hash * 23 + this.Name == null ? 0 : this.Name.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)

它与你的相似 - 我删除了无法编译的部分.

Name设置为null (演示)时,此功能将以您GetHashCode()想要的方式崩溃.这看起来很奇怪,因为乍一看检查的性能null是存在的.

但是,检查它是错误的null:C#与null整个表达式进行比较:

hash * 23 + this.Name
Run Code Online (Sandbox Code Playgroud)

这是一个有效的字符串连接.

这提供了一个线索,以解决您的"玄机":这是不是说其实Bar是一个集合错误导致编译错误,但事实证明Namestring被错误地避免编译错误.