Description
When using BinaryWriter.Write(string), it attempts to optimize the performance, and when the value is short enough (and the encoding is UTF8), then the operation may bypass the Write7BitEncodedInt call.
But this is a problem if we use a derived BinaryWriter where the Write(int) method is overridden because the Write7BitEncodedInt method calls the virtual Write(int) method.
Example: we have a pair of reader-writer that dumps the written/read values while adjusts the current position. Since BinaryReader always calls the Read7BitEncodedInt method, the dumped information and offsets slowly drift away when short strings are written:

Reproduction Steps
- Create a derived
BinaryWriter with an overridden Write(int) method.
- Call
Write(string) with various lengths
- Observe that the overridden
Write(int) is sometimes called, sometimes not, depending on string length.
Expected behavior
BinaryWriter and BinaryReader should have a symmetric behavior. When we have a derived BinaryWriter class, I always expect the overridden Write(int) method to be called because that's how BinaryReader also works (ie. its ReadString always calls ReadInt32).
Actual behavior
BinaryWriter.Write(string) sometimes calls the implicit Write(int) method, sometimes not. See the details above.
Regression?
It works in .NET Framework, and it worked in .NET 5.0.
Known Workarounds
Duplicating the old behavior in a derived class without calling base.Write(string) (a bit painful).
Configuration
Noticed in .NET 9 Preview 7 but it turns out that we have this behavior since .NET 6.0
Other information
Possible solutions:
- Check in the base constructor if the current type is a derived one, and if so, then initialize the
_useFastUtf8 field to false.
- Or, allow only the "semi-optimized" branch, which still calls the
Write7BitEncodedInt method,
Description
When using
BinaryWriter.Write(string), it attempts to optimize the performance, and when the value is short enough (and the encoding is UTF8), then the operation may bypass theWrite7BitEncodedIntcall.But this is a problem if we use a derived
BinaryWriterwhere theWrite(int)method is overridden because theWrite7BitEncodedIntmethod calls the virtualWrite(int)method.Example: we have a pair of reader-writer that dumps the written/read values while adjusts the current position. Since
BinaryReaderalways calls theRead7BitEncodedIntmethod, the dumped information and offsets slowly drift away when short strings are written:Reproduction Steps
BinaryWriterwith an overriddenWrite(int)method.Write(string)with various lengthsWrite(int)is sometimes called, sometimes not, depending on string length.Expected behavior
BinaryWriterandBinaryReadershould have a symmetric behavior. When we have a derivedBinaryWriterclass, I always expect the overriddenWrite(int)method to be called because that's howBinaryReaderalso works (ie. itsReadStringalways callsReadInt32).Actual behavior
BinaryWriter.Write(string)sometimes calls the implicitWrite(int)method, sometimes not. See the details above.Regression?
It works in .NET Framework, and it worked in .NET 5.0.
Known Workarounds
Duplicating the old behavior in a derived class without calling
base.Write(string)(a bit painful).Configuration
Noticed in .NET 9 Preview 7 but it turns out that we have this behavior since .NET 6.0
Other information
Possible solutions:
_useFastUtf8field tofalse.Write7BitEncodedIntmethod,