The innocuous code that tripped me
When building a cache, I need a way to generate a hash code from a query. A query is a complex object that has many properties. My first attempt to do so looked like this:
And it failed, disastrously. All queries always had the same hash code, and I couldn’t figure out why until I actually debugged through the code.
Here is a hint, this only happened if WaitForNonStaleResultsTimeout is null. It might be better to also look at the way the compiler looks at this:
Basically, if WaitForNonStaleResultsTimeout is null, the entire expression evaluated to null, so we return zero, losing all the previous hash values that we put in.
The solution was to parenthesis the expression, but this is something that passed a couple rounds of scrutiny and didn’t show up at all, because it looked fine, and I don’t keep the precedence rules for operators in C# in my head.
Comments
Isn't is safier to calculate the hash codes in unchecked context?
Doesn't Nullable<T>.GetHashCode do exactly what you want by default? It decompiles to
Resharper does this right (part of 'generate equality members', by the way.
I've been bitten by this too.
?? and :? are really low precedence and I think it's very important to remember that when writing C# expressions even if one doesn't know the precedence from memory. Only assignment is lower than Null coalescing and conditional.
I bracket just about everything. I hate interactive query builders that have the screen like
because the precedence rules are not at all clear. Grrrr.
Would you mind showing where exactly you placed the parentheses? Is that only around the
?.
expression?kpvleeuwen, The problem is that the
^
is higher priority, then??
, so it evaluated , but it gave _null_, so the value of the hash was always0
.Comment preview