Skip to content

Fix Int128/UInt128 serialization and JValue comparison logic - #3106

Open
KitKeen wants to merge 6 commits into
JamesNK:masterfrom
KitKeen:fix_cant_deser_int128
Open

Fix Int128/UInt128 serialization and JValue comparison logic#3106
KitKeen wants to merge 6 commits into
JamesNK:masterfrom
KitKeen:fix_cant_deser_int128

Conversation

@KitKeen

@KitKeen KitKeen commented Apr 12, 2026

Copy link
Copy Markdown

This PR improves the handling of Int128 and UInt128 types to ensure they are treated as native numeric values rather than strings during serialization. It also implements correct equality and comparison logic within JValue.

Key changes:

Numeric Serialization: Fixed an issue where Int128/UInt128 were serialized as strings. They are now correctly serialized as raw JSON numbers.

Deserialization: Ensured that large 128-bit integers can be correctly deserialized from JSON numbers without precision loss or format errors.

JValue Logic: Updated JValue.Equals and JValue.CompareTo to support 128-bit integer types, enabling proper sorting and comparison in LINQ to JSON.

Comment on lines +658 to +682
public override Task WriteValueAsync(Int128 value, CancellationToken cancellationToken = default)
{
return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
}

internal Task DoWriteValueAsync(Int128 value, CancellationToken cancellationToken)
{
return WriteValueInternalAsync(JsonToken.Integer, value.ToString(CultureInfo.InvariantCulture), cancellationToken);
}

/// <summary>
/// Asynchronously writes a <see cref="UInt128"/> value.
/// </summary>
/// <param name="value">The <see cref="UInt128"/> value to write.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous operation.</returns>
public override Task WriteValueAsync(UInt128 value, CancellationToken cancellationToken = default)
{
return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
}

internal Task DoWriteValueAsync(UInt128 value, CancellationToken cancellationToken)
{
return WriteValueInternalAsync(JsonToken.Integer, value.ToString(CultureInfo.InvariantCulture), cancellationToken);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to support this without adding new public methods? Is calling WriteValue(object) enough? Performance will suffer because the value is boxed, but it means existing implementations don't need to worry about implementing the new overloads.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix it without adding new public methods, I'm working on it, I'll let you know when I've finished, thank you.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I've refactored it exactly as you suggested. The public WriteValue(Int128) / WriteValue(UInt128) overloads are removed. Instead, Int128 and UInt128 are handled in the existing WriteValue(object) path via pattern matching in JsonTextWriter. Existing JsonWriter implementations don't need any changes. The boxing overhead is acceptable since these types are rare in practice.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the CS0234 build error: moved usings inside the #if HAVE_INT128 guard for net20/net35 compatibility. James, could you possiblly rerun the workflow?

@KitKeen KitKeen Apr 22, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a kind reminder!

@KitKeen
KitKeen force-pushed the fix_cant_deser_int128 branch from 53c465c to 39b10fb Compare April 13, 2026 12:43
@KitKeen
KitKeen requested a review from JamesNK April 20, 2026 07:47
…, and cross-type comparison coverage; enable HAVE_INT128 in test csproj
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants