Coding Faster with dotNetTips.com Spargine 10: October 2026 Release

I am delighted to announce the release of Spargine 10 (v2026.10.10.1) on October 1st, 2026. Spargine, my open-source project, now offers NuGet packages for .NET 10. I’ve integrated these enhancements across all my projects. I encourage you to explore these updates and share any feedback or suggestions for further improvements.

This version supports .NET 10, introduces new types, methods, benchmarks, and comprehensive unit tests, all aimed at improving Spargine’s performance and reliability! Notably, this release includes speed enhancements informed by benchmark tests outlined in the 5th edition of Rock Your Code: Code & App Performance for Microsoft .NET, available on Amazon.

GitHub: https://github.com/RealDotNetDave/dotNetTips.Spargine.10/releases

NuGet: http://bit.ly/dotNetDaveNuGet

You can access all the performance data for these assemblies on GitHub. I’m always seeking help with these projects. If you are interested in contributing, please don’t hesitate to contact me via email at dotnetdave@live.com. Your support and collaboration are highly appreciated!

New Classes and Methods

Below are the new classes and methods added to this version of Spargine.

dotNetTips.Spargine

TypeMethodDescription
HttpClientHelperCreateOptimizedHttpClient()Creates a new, performance-optimized HttpClient instance configured with the specified options.

dotNetTips.Spargine.Core

TypeMethodDescription
TaskHelperGetUnderlyingType()Gets the underlying type for a nullable type.
TaskHelperRunSync()Executes the specified asynchronous ValueTask synchronously on a background thread. Overloaded to also return a TResult.
ThreadPoolHelper
* New Type
RunAsync()Queues an operation to the managed thread pool and waits for the result.
ThreadPoolHelperRunWhenAnyAsync()Queues multiple operations to the managed thread pool and returns the result of the first operation to complete.
ThreadPoolHelperTryRunAsync()Queues an operation to the managed thread pool and captures the outcome in a SimpleResult without throwing on failure.
ThreadPoolHelperGetStatistics()Gets a point-in-time snapshot of the managed thread pool statistics.

dotNetTips.Spargine.Extentions

TypeMethodDescription
CollectionExtensionsAddRangeIfNotExists()Adds items from items to the collection only when they do not already exist.
CollectionExtensionsRemoveWhere()Removes each item from the collection that satisfies the supplied predicate.
CollectionExtensionsTryGetFirst()Tries to get the first item in the sequence without throwing or allocating an enumerator when the source is an IList.
DateTimeExtensionsClamp()Clamps a DateTime to the inclusive range defined by minimum and maximum.
DateTimeExtensionsEndOfDay()Returns the last tick of the day for the specified DateTime or DateTimeOffset.
DateTimeExtensionsRoundToNearestMultiple()Rounds a DateTime to the nearest multiple of multiple.
DateTimeExtensionsStartOfDay()Returns midnight (00:00:00) of the DateTime or DateTimeOffset.
DateTimeExtensionsToDateOnly()Converts a DateTime to a DateOnly representing only the date component.
DateTimeExtensionsToTimeOnly()Converts a DateTime to a TimeOnly representing only the time component.
DateTimeExtensionsTryParseInvariant()Attempts to parse a DateTime from a ReadOnlySpan using invariant culture.
DictionaryExtensions
* New type
GetOrAdd()Gets the value associated with the specified key, or adds a newly created value from valueFactory.
DictionaryExtensionsTryGetValueOrDefault()Gets the value associated with the specified key, or returns defaultValue when the key is not found.
DictionaryExtensionsTryRemoveAndReturn()Attempts to remove the value with the specified key and returns the removed value when found.
DirectoryInfoExtensionsReadAllTextSafe()Reads all text from the file in this directory and returns a fallback when the read fails.
DirectoryInfoExtensionsWriteAllTextAtomic()Writes text atomically to a file within the directory.
DirectoryInfoExtensions

CreateTempFileThenMove()Creates a temporary file in a directory and atomically moves it to a destination.
EfCoreModelBuilderExtensions
* New type
RegisterEnumAsStringConverters()Registers enum-to-string value converters for all enum and nullable enum properties in the current model. Existing property-level converters are preserved.
FileInfoExtensionsCreateTempFileThenMove()Creates a temporary file in the same directory and atomically moves it to a new file.
FileInfoExtensionsReadAllTextSafe()Reads all text from the file and returns a fallback when file access fails.
FileInfoExtensionsWriteAllTextAtomic()Writes text atomically by writing to a temp file then moving/replacing the target file.
MemoryExtensions
*New type
IsEqualTo()Determines whether the current Memory is equal to other by comparing elements.
MemoryExtensionsToArrayIfNeeded()Returns the elements of this Memory as an array, avoiding a copy when possible.
MemoryExtensionsTryGetArraySegment()Attempts to retrieve the underlying ArraySegment that backs this Memory without copying.
MemoryExtensionsIsNotEmpty()Determines whether the Memory contains any elements.
MessagePackExtensions
*New type
ToMessagePackBytes()Serializes the specified value to MessagePack bytes.
MessagePackExtensionsFromMessagePack()Deserializes the specified MessagePack bytes into an instance of T.
NumericExtensionsClamp()Clamps an int to the inclusive range defined by minimum and maximum.
NumericExtensionsRoundToNearestMultiple() Rounds an int to the nearest multiple of multiple using midpoint rounding away from zero.
NumericExtensionsTryParseInvariant()Attempts to parse an int from a ReadOnlySpan using invariant culture.
OpenTelemetryExtensions
* New type
SetStatusIfError()Sets the activity status to ActivityStatusCode.Error when an exception is present.
OpenTelemetryExtensionsAddTagsIfPresent()Adds tags to an Activity when both key and value are present.
ReadOnlyMemoryExtensions
* New type
IsEqualTo()Determines whether the current ReadOnlyMemory is equal to other by comparing elements.
ReadOnlyMemoryExtensionsToArrayIfNeeded()Returns the elements of this ReadOnlyMemory as an array, avoiding a copy when possible.
ReadOnlyMemoryExtensionsTryGetArraySegment()Attempts to retrieve the underlying ArraySegment that backs this ReadOnlyMemory without copying.
ReadOnlyMemoryExtensionsIsNotEmpty()Determines whether the ReadOnlyMemory contains any elements.
StreamExtensionsCopyToAsyncPooled()Copies all bytes from a source to a destination asynchronously using a pooled buffer.
StreamExtensionsReadExactlyAsync()Reads exactly buffer.Length bytes from a stream.
StreamExtensionsWriteAllAsync()Writes all bytes from a buffer to a stream asynchronously.
StringExtensionsFormatCurrentCulture()Formats the specified composite format using CultureInfo.CurrentCulture and cached CompositeFormat parsing.
StringExtensionsFormatInvariant()Formats the specified composite format using CultureInfo.InvariantCulture and cached CompositeFormat parsing.
StringExtensionsJoinFormatted()Formats each value in args using the specified composite format and joins the results using delimiter.
TaskExtensionsIqnoreCancellation()Observes the task and suppresses cancellation exceptions while allowing other exceptions to propagate.
TaskExtensionsUnwrapAggregate()Returns the innermost single exception when the source is an AggregateException; otherwise returns the original exception.
TaskExtensionsWithTimeoutAsync()Awaits completion of the task within the specified timeout.

dotNetTips.Spargine.Benchmark

TypeMethodDescription
BenchmarkConsumeAsyncEnumerableAsync()Enumerates and consumes every element of an asynchronous sequence.
BenchmarkCreateTemporaryDirectory()Creates a unique temporary directory owned by this benchmark instance.
BenchmarkGetByteArrayByLength()Retrieves a cached mutable byte array with an exact length, including zero.
BenchmarkGlobalCleanupAsync()Awaits the cleanup hook and then removes this instance’s tracked temporary directories.
BenchmarkGlobalSetupAsync()Optionally launches the debugger and dispatches asynchronous benchmark initialization.
CollectionBenchmarkClearCollectionCaches()Clears all in-memory collection caches held by this benchmark instance.
CollectionBenchmarkClearPersonCaches()Clears the in-memory person collection caches and replaces them with empty lists.
CollectionBenchmarkCopyCoordinateValTo()Copies the internal value-type coordinate buffer into the provided destination span.
CollectionBenchmarkGetCoordinateRefArray()Gets a clone of the Coordinate array. This method ensures that benchmarks operate on a fresh copy of the data, preventing modifications from affecting subsequent benchmark runs.
CollectionBenchmarkGetCoordinateRefCollection()Gets a clone of the Coordinate list as a Collection<T>.
CollectionBenchmarkGetCoordinateRefReadOnlySpan()Returns a ReadOnlySpan over the internal reference-type coordinate array.
CollectionBenchmarkGetCoordinateValArray()Gets a clone of the Coordinate array. This method ensures that benchmarks operate on a fresh copy of the data, preventing modifications from affecting subsequent benchmark runs.
CollectionBenchmarkGetCoordinateValCollection()Gets a clone of the Coordinate list as a Collection<T>.
CollectionBenchmarkGetCoordinateValReadOnlySpan()Returns a ReadOnlySpan over the internal value-type coordinate array.
CollectionBenchmarkGetPersonRecordCollectionToInsert()Gets a collection of PersonRecord objects for insertion into collections.
CollectionBenchmarkGetPersonRecordDictionary()Gets a cloned dictionary for PersonRecord.
CollectionBenchmarkGetPersonRecordReadOnlySpan()Returns a read-only span over the internal PersonRecord list.
CollectionBenchmarkGetPersonRefCollectionToInsert()Gets a collection of Person reference objects for insertion into collections.
CollectionBenchmarkGetPersonRefReadOnlySpan()Returns a read-only span over the internal Person reference-type list.
CollectionBenchmarkGetPersonValCollectionToInsert()Gets a collection of ValueTypes.Person value objects for insertion into collections.
CollectionBenchmarkGetPersonValDictionary()Gets clone of person value dictionary.
CollectionBenchmarkGetPersonValReadOnlySpan()Returns a read-only span over the internal Person value-type list.
CollectionBenchmarkLoadCoordinateCollections()Loads the coordinate collections into memory. This includes both a list and an array of Coordinate objects, populated to the maximum count specified for the benchmark. This method is called to prepare data for benchmark tests.
CollectionBenchmarkReloadCollections()Reloads the coordinate and person collections and refreshes the lookup values.
CollectionBenchmarkTryFindPersonRefById()Attempts to find a Person reference with the specified id in the internal list.
ReturnValueColumnConfig
*New Type
Provides a ManualConfig that adds the ReturnValueColumn to BenchmarkDotNet output.

dotNetTips.Spargine.Tester

TypeMethodDescription
RandomDataGenerateBoolean()Generates a random boolean value.
RandomDataGenerateCompanyName()Generates a random company name.
RandomDataGenerateCurrencyAmount()Generates a random currency amount with the specified decimal places.
RandomDataGenerateDateOnly()Generates a random DateOnly within a specified range.
RandomDataGenerateDateTimeOffset()Generates a random DateTimeOffset within a specified range.
RandomDataGenerateEnum()Generates a random value from the specified enum type.
RandomDataGenerateGuid()Generates a new GUID value.
RandomDataGenerateHashString()Generates a random hexadecimal hash string of the specified length.
RandomDataGenerateIPv4Address()Generates a random IPv4 address string.
RandomDataGenerateIPv6Address()Generates a random IPv6 address string.
RandomDataGenerateJsonObject()Generates a random JSON object string with the specified number of properties.
RandomDataGenerateParagraph()Generates a random paragraph with the specified number of sentences.
RandomDataGenerateSentence()Generates a random sentence with the specified number of words.
RandomDataGenerateTimeOnly()Generates a random TimeOnly within a specified range.
RandomDataGenerateTimeSpan()Generates a random TimeSpan within a specified range.

Performance Enhancements: Significant Speed Improvements Across Methods

With every new release of Spargine, I continue to refine performance, reduce allocations, and improve the library’s overall efficiency. The .NET 10 version delivers substantial speed gains through many methods, with several benchmarks showing significant improvements.

Some of these gains came from careful tuning, repeated benchmarking, and focused code reviews. I also tested performance recommendations from Copilot, although the results were mixed. At the moment, roughly 60% of the performance changes suggested by Copilot make the method slower, which is a good reminder that every optimization must be validated with real benchmarks.

The results below highlight some of the most notable performance gains in this release, specifically methods that improved by 2x or more. In several cases, allocations also dropped dramatically, and some methods reduced allocations by 100%. That is a major win for performance-sensitive applications.

In this release, 340 methods in Spargine showed performance improvements. Here are the most notable speed increases:

  • App.ProcessId(): 2.45x faster
  • ArrayExtensions.AreEqual(): 2.3x faster
  • CharacterExtensions.ToAsciiLower(): 87.52x faster
  • CharacterExtensions.ToAsciiUpper(): 13.26x faster
  • DirectoryHelper.SetFileAttributesToNormal(): 39.08x faster
  • EnumerableExtensions.FastLongCount(): 3.38x faster
  • EnumerableExtensions.IsEmpty([]): 2.89x faster.
  • FileHelper.FileHasInvalidChars(): 12.42x faster
  • ObjectExtensions.IsNotNull(): 17.03x faster.
  • PathHelper.HasInvalidFilterChars(): 26.15x faster
  • PathHelper.PathHasInvalidChars(): 7.01x faster
  • StringExtensions.HasValue(): 14.49x faster.

Summary

I’m confident these new and enhanced Spargine features will significantly improve your projects by boosting both performance and reliability. Detailed benchmark results are available on GitHub for those who want to dig deeper.

As always, open-source thrives on community involvement. If you find these updates helpful — or have ideas for future improvements — I encourage you to jump in. Whether through pull requests, issue reports, or feature suggestions, your contributions are invaluable.

Together, we can continue to make Spargine a robust and indispensable tool for the .NET community. Your feedback is always welcome, so please share your thoughts in the comments.

If my work has helped you write faster, cleaner, rock-solid .NET code, I’d love your support through GitHub Sponsors. Your sponsorship helps fuel new features, benchmarks, tools, and learning resources for the entire community. Join the crew here: https://github.com/sponsors/RealDotNetDave — and thanks for helping keep the code loud and fast!Thank you for your support — and keep coding faster, smarter, and better!

Do you have suggestions for Spargine?

If I use your suggestion and you live in the US or a country I am traveling to, to speak at a conference, I will send you some cool geeky swag!

← Back

Thank you for your response. ✨

Thank you so much for the suggestion.

Pick up any books by David McCarter by going to Amazon.com: http://bit.ly/RockYourCodeBooks

If you liked this article, please buy David a cup of Coffee by going here: https://www.buymeacoffee.com/dotnetdave

© The information in this article is copywritten and cannot be reproduced in any way without express permission from David McCarter.


Discover more from dotNetTips.com

Subscribe to get the latest posts sent to your email.

Leave a Reply