Print(Decimal.MaxValue)
Var testValue As Decimal = (Decimal.MaxValue - 1d) + 0.1234567d
Print(testValue)
Expected output:
79228162514264337593543950335
79228162514264337593543950334.12345
Actual output:
79228162514264337593543950335
79228162514264337593543950334
Correct output, now that I think of it:
An exception for out of range or overflow.
I was looking for a value not quite MaxValue but while 79228162514264337593543950334.12345 would be such a value in theory, in practice it exceeds the maximum # of digits that Decimal can handle. So Decimal, past 28 digits, can only express whole numbers, past 27 digits can only handle one decimal place, etc. (and while I haven't tested it, I suspect you have to subtract one digit from those limits for negative values as it appears the sign takes up an extra nibble in the storage format).
In this sense MaxValue and MinValue are not that helpful because they imply they are ends of an uninterrupted range. But I guess that is somewhat true of Double as well; in both cases, the further you get from zero, the more "gaps" there are in the values that can be (accurately) expressed. It's just that the nature of the gaps is rather different and in the case of Decimal, far more deterministic. You can predict how many decimal places you could express based on the total number of digits and the sign, and the values that are valid are at least exact and not subject to rounding.
This is new territory for me because historically I have only used Decimal in C# because there's no Currency alternative, and I've been using it as a Currency substitute and so even for large, multinational corporation-scale monetary values, I never flirt with these edge cases, even going out to say 4 decimal places for intermediate values when doing currency conversions, etc.
Nevertheless I feel that silent truncation isn't the way to handle this, even if the underlying .NET implementation does it that way. Maybe it's a performance tradeoff, IDK. Just thought it should be surfaced and considered. If it's gnarly or slows things way down to handle this the way I suggest, then I'd certainly settle for it being explicitly documented.
ETA: The more I think about this the more I think it's a documentation issue. Regardless of how unrepresentable values are handled, they exist and you just need to understand your use case in advance. If your use case is large integers exceeding the Int64 range into the octillions, then MaxValue <=> MinValue represents an unbroken range of possibilities. Otherwise you limit your range to 28 or 29 digits minus the number of decimal places you need available and you still know your unbroken range based on that.