[CSHARP-1718] Cannot deserialize floats from json Created: 21/Jul/16 Updated: 25/Jul/16 Resolved: 25/Jul/16 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | BSON |
| Affects Version/s: | 2.2.4 |
| Fix Version/s: | None |
| Type: | Bug | Priority: | Critical - P2 |
| Reporter: | Toshko Andreev [X] | Assignee: | Robert Stam |
| Resolution: | Done | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Environment: |
Ubuntu Server 14.04 LTS x64 |
||
| Backwards Compatibility: | Fully Compatible |
| Description |
|
If you have a RootClass with a SubClass as a child property and it has two float properties then BsonSerializer.Deserialize<TheClass>(json); will throw an error saying that it cannot deserialize the second float. See this gist for re-pro code: https://gist.github.com/Ravenheart/0f4f47bbe14737cb01998cf86bf0396d This error occurs in ALL versions of the C# driver, including the legacy one. |
| Comments |
| Comment by Robert Stam [ 25/Jul/16 ] | ||||||||||||
|
You're welcome. Glad you got it working for you. | ||||||||||||
| Comment by Toshko Andreev [X] [ 25/Jul/16 ] | ||||||||||||
|
Thank you Robert for the detailed explanation and support. I have corrected my code with the attribute fix. | ||||||||||||
| Comment by Robert Stam [ 22/Jul/16 ] | ||||||||||||
|
It fails on the second property because 2.9 cannot be exactly represented as a binary floating point number, and when the closest available double value is converted to a float there is loss of precision (recall that floats only use 64 bits and doubles use 128 bits). You can make it fail on the first property by just swapping the values (0.5 and 2.9). It's not true that all values above 0.5 fail. You can try 0.75 for example. It only fails when there is a loss of precision when converting from a double to a float (which typically will be the case when the fractional decimal value does not have an exact representation as a binary double). It's also not true that anything below 0.5 works fine. Try 0.3 for example. If you can use double instead of float in your class this problem disappears. Otherwise you will have to decide whether you are willing to lose precision when converting doubles to floats and if so tell the driver that by annotating your class. | ||||||||||||
| Comment by Toshko Andreev [X] [ 22/Jul/16 ] | ||||||||||||
|
Why does it throw the error on the second property then, and why does it only happen if the value is above 0.5 (anything below that and it works fine). | ||||||||||||
| Comment by Robert Stam [ 21/Jul/16 ] | ||||||||||||
|
This error is happening because BSON only has double values, not floats. The driver serializes floats as doubles, but when converting doubles read from the database back to floats a loss of precision can occur. When the double value cannot exactly be represented as a float the driver throws an exception. There are two things you could do to get this code working. The easiest is to just use doubles instead of floats:
The other is to annotate the class to tell the driver that you are OK with losing precision during deserialization:
Just be aware that in the second case you are losing precision, and if you read a document from the database and write it back the value written back to the database will be slightly different (due to rounding errors when converting from double to float and back to double). |