.NET 10 generic math shift masking changes the result of some oversized shifts on small integer types. If a helper uses IShiftOperators<T, int, T>, code such as a generic byte << 8 can return 1 on .NET 10 where it returned 0 on .NET 9. That is a narrow behavioral change, but it can matter in bit-field parsing, binary protocols, compact identifiers, and any test fixture that treats an out-of-range count as an implicit zero.

I treat this as a contract problem. The runtime now behaves consistently; the application still has to decide whether an oversized count is valid.

Why .NET 10 generic math shift masking changes results

The official breaking-change note says generic shifts now mask the shift amount as appropriate for all built-in integer types. The affected small types are byte, char, sbyte, short, and ushort, and the affected operators are <<, >>, and >>>.

This is specifically about operators dispatched through generic math. A concrete C# expression involving a byte can be promoted to int; a generic method constrained by IShiftOperators<T, int, T> returns T. That distinction is why a normal happy-path unit test may not reveal the upgrade boundary.