Add the BitConverter span overloads for netstandard2.0 and .NET Framework - #599
Merged
Conversation
…work Twenty members: ToBoolean, ToChar, ToInt16, ToInt32, ToInt64, ToSingle, ToDouble, ToUInt16, ToUInt32 and ToUInt64 over a ReadOnlySpan, and the matching TryWriteBytes. Confirmed against the reference assemblies to be missing on net461 through net481, netstandard2.0 and netcoreapp2.0, and present from netstandard2.1 and netcoreapp2.1, so the guard is the pattern already used elsewhere in the repo. Reads and writes go through MemoryMarshal, as BinaryPrimitivesPolyfill already does, which reads unaligned and does not copy. ToBoolean is done by hand rather than reinterpreting the byte, since any non-zero byte is true and a non-canonical bool is not something to create deliberately. Verified against net11: a short span is rejected with a plain ArgumentOutOfRangeException naming value, not the ArgumentException the array overloads use for the same shape; TryWriteBytes leaves the destination untouched when it refuses; and a larger destination is written only up to the width of the value. The tests read at odd offsets, which would fault or misread under an implementation that assumed alignment, and run on every target, so netstandard2.1 and later check the BCL while net462 checks the polyfill. API count 1119 -> 1139.
This was referenced Sep 10, 2026
This was referenced Sep 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #598, which flagged these while diffing the type. Twenty members: the ten
To*(ReadOnlySpan<byte>)reads and the ten matchingTryWriteBytes(Span<byte>, T)writes, forbool,char,short,int,long,float,double,ushort,uintandulong.Availability confirmed against the reference assemblies
So the guard is
!NETCOREAPP2_1_OR_GREATER && !NETSTANDARD2_1_OR_GREATER, which is the patternConvertPolyfill,GuidPolyfill,EncodingPolyfilland others already use. This is the oldest-target end of the range, where these are arguably most useful — it is the group that has no span-based conversion at all today.Implementation
Reads and writes go through
MemoryMarshal.Read<T>/MemoryMarshal.Write<T>, which is exactly whatBinaryPrimitivesPolyfillalready does under the sameFeatureMemoryconstraint. That reads unaligned, which matters: span offsets are arbitrary, and the tests deliberately read at offsets 1, 3 and 5 so an implementation assuming alignment would fault or misread. It also avoids copying, so these are not the "correct but allocates" compromise — no//Note:needed on any of the twenty.ToBooleanis the one done by hand, asvalue[0] != 0. Reinterpreting the byte as aboolviaMemoryMarshalwould produce a non-canonicalboolfor inputs like2, which is not something to create deliberately even though it happens to test as true.Semantics verified against net11
ArgumentOutOfRangeExceptionnamingvalue— not theArgumentExceptionthe array overloads throw for the equivalent "index valid but too few bytes remain" case. The two families genuinely differ here, and Add net9 BitConverter Int128 and UInt128 members #598 matched the array behaviour for the same type, so getting this the other way round would have been an easy mistake.TryWriteBytesleaves the destination untouched when it refuses, rather than partially writing.0xAAand checking the tail survives.ToBooleantreats any non-zero byte astrue, matching the array overload.Tests
Four tests, running on every target framework, so netstandard2.1/netcoreapp2.1 and later check the BCL and net462 checks the polyfill — all four pass on both sides. Reads are cross-checked against the corresponding array overload at each offset rather than against expected constants, which is an oracle the polyfill has no part in.
Result
API count 1119 → 1139.
Solution clean in Release, Consume clean across all 22 TFMs, tests green on net11.0 (1710), net10.0 (1710), net9.0 (1710), net8.0 (1707), net462 (1665), plus PublicTests, EmbeddedTests, UnsafeTests, NoRefsTests and NoExtrasTests.