-
Notifications
You must be signed in to change notification settings - Fork 6
Add support for deserializing numbers from strings #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for deserializing numbers from strings #68
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for the JsonNumberHandling.AllowReadingFromString option when deserializing protobuf messages with System.Text.Json. This allows numeric fields to be deserialized from JSON string values when the appropriate option is enabled.
- Added logic in
FieldConverter<T>to handle string-to-number conversions whenJsonNumberHandling.AllowReadingFromStringis set - Added comprehensive test coverage for both successful and failure scenarios
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/Protobuf.System.Text.Json/InternalConverters/FieldConverter.cs |
Implements number-from-string deserialization support with appropriate type checking and conversion logic |
test/Protobuf.System.Text.Json.Tests/JsonNumberHandlingTests.cs |
Adds test cases to verify number-from-string conversion works correctly when enabled and fails when disabled |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| using System.Buffers; | ||
| using System.Diagnostics; |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The System.Buffers and System.Diagnostics namespaces are imported but not used in this file. Remove these unused imports.
| using System.Buffers; | |
| using System.Diagnostics; |
|
|
||
| if (_isConverterForNumberType && reader.TokenType == JsonTokenType.String && (JsonNumberHandling.AllowReadingFromString & options.NumberHandling) != 0) | ||
| { | ||
| var value = Convert.ChangeType(reader.GetString(), typeToConvert); |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Convert.ChangeType without specifying CultureInfo.InvariantCulture can lead to culture-dependent parsing issues. JSON numbers should always use invariant culture (decimal point, not comma). Additionally, Convert.ChangeType can throw FormatException or InvalidCastException which are not wrapped in JsonException, making error handling inconsistent with the rest of the deserializer. Consider using type-specific parsing methods (e.g., double.Parse, int.Parse) with NumberStyles and CultureInfo.InvariantCulture, and wrap exceptions in JsonException.
|
|
||
| if (_isConverterForNumberType && reader.TokenType == JsonTokenType.String && (JsonNumberHandling.AllowReadingFromString & options.NumberHandling) != 0) | ||
| { | ||
| var value = Convert.ChangeType(reader.GetString(), typeToConvert); |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Convert.ChangeType with reflection-based type conversion is significantly slower than type-specific parsing. For numeric types, consider using a switch statement on Type.GetTypeCode(typeToConvert) with direct calls to Parse methods for each type (e.g., int.Parse, double.Parse, etc.), which will be more performant.
| var value = Convert.ChangeType(reader.GetString(), typeToConvert); | |
| object value; | |
| var str = reader.GetString(); | |
| switch (Type.GetTypeCode(typeToConvert)) | |
| { | |
| case TypeCode.Byte: | |
| value = byte.Parse(str); | |
| break; | |
| case TypeCode.SByte: | |
| value = sbyte.Parse(str); | |
| break; | |
| case TypeCode.Int16: | |
| value = short.Parse(str); | |
| break; | |
| case TypeCode.UInt16: | |
| value = ushort.Parse(str); | |
| break; | |
| case TypeCode.Int32: | |
| value = int.Parse(str); | |
| break; | |
| case TypeCode.UInt32: | |
| value = uint.Parse(str); | |
| break; | |
| case TypeCode.Int64: | |
| value = long.Parse(str); | |
| break; | |
| case TypeCode.UInt64: | |
| value = ulong.Parse(str); | |
| break; | |
| case TypeCode.Single: | |
| value = float.Parse(str); | |
| break; | |
| case TypeCode.Double: | |
| value = double.Parse(str); | |
| break; | |
| case TypeCode.Decimal: | |
| value = decimal.Parse(str); | |
| break; | |
| default: | |
| throw new JsonException($"Unsupported numeric type: {typeToConvert}"); | |
| } |
No description provided.