NuExt.System is a lightweight, production-ready foundation for everyday .NET development. It brings together high-quality utilities for asynchrony, lifetime management, threading primitives, high‐performance spans/memory helpers, diagnostics, and collection helpers — all with a strong focus on performance, correctness, and developer ergonomics. Use it to reduce boilerplate, standardize common patterns across projects, and keep code fast and clean across modern .NET and .NET Framework.
- Asynchrony & lifetime
- Async locks and wait handles:
AsyncLock,ReentrantAsyncLock,AsyncWaitHandle - Disposable tooling:
Disposable,AggregateDisposable,AsyncDisposable,AggregateAsyncDisposable,AsyncLifetime
- Async locks and wait handles:
- Threading & synchronization
- Reentrant async lock (context‐aware), synchronization‐context helpers, thread‐affine flows
- High‐performance spans & memory
- Backports/polyfills for
Span/MemoryExtensionsAPIs (see below) ValueStringBuilder/ValueListBuilder<T>for zero‐allocation building
- Backports/polyfills for
- Collections & equality
ObservableDictionary<TKey, TValue>,ReferenceEqualityComparer(polyfill),ArrayEqualityComparer<T>, and many useful extension helpers
- I/O & paths (cross‐platform)
PathBuilder(class,IDisposable) andValuePathBuilder(ref struct) — platform‐independent path buildersPathUtilities— static helpers for common path operations
- Diagnostics & utilities
ProcessMonitor,PerformanceMonitor,EnumHelper<T>,TypeExtensions, etc.
This package includes polyfills (API backports) for selected Span / MemoryExtensions‐style APIs from newer .NET versions. On modern runtimes, it transparently uses the inbox implementations; on older runtimes, it provides compatible behavior with the same semantics.
What you get (highlights)
- Search & comparison:
Contains,SequenceEqual(+IEqualityComparer<T>) - Indexing:
IndexOf,LastIndexOf(element / sequence) - Set‐based search:
IndexOfAny,LastIndexOfAny,IndexOfAnyExcept,LastIndexOfAnyExcept - Range‐based:
IndexOfAnyInRange,IndexOfAnyExceptInRange,LastIndexOfAnyInRange,LastIndexOfAnyExceptInRange - Utilities:
StartsWith,EndsWith,Replace(in‐place / copy),Count,CountAny
Notes
- Allocation‐free, performance‐oriented; value types use bitwise fast paths where applicable.
- Semantics mirror the .NET runtime APIs; custom comparers are honored when provided.
- Practical — battle‐tested building blocks you use every day
- Fast — zero‐alloc paths, tight loops, careful branching profiles
- Consistent — same behavior across modern .NET and .NET Framework
- Focused — no heavy external dependencies or configuration
- .NET Standard 2.0+, .NET 8/9/10 and .NET Framework 4.6.2+
- Works across desktop, web, and services (Console, ASP.NET Core, Avalonia, WinUI, WPF, WinForms)
- Asynchrony & lifetime
System.Threading.AsyncLock,System.Threading.ReentrantAsyncLock,System.Threading.AsyncWaitHandleSystem.ComponentModel.Disposable,AggregateDisposable,AsyncDisposable,AggregateAsyncDisposable,AsyncLifetime
- Collections & equality
System.Collections.ObjectModel.ObservableDictionary<TKey, TValue>System.Collections.Generic.ValueListBuilder<T>System.Collections.Generic.ReferenceEqualityComparer(polyfill)System.Collections.Generic.ArrayEqualityComparer<T>- Various extension helpers (collections, delegates, enums, strings, exceptions)
- Strings, spans, and memory
System.Text.ValueStringBuilderSystem.CompatMemoryExtensions(polyfills/backports)
- I/O & paths (cross‐platform)
System.IO.PathBuilder(class,IDisposable— mutable path builder)System.IO.ValuePathBuilder(ref struct — high‐performance mutable path builder)System.IO.PathUtilities(static common path operations)
- Diagnostics & helpers
System.Diagnostics.ProcessMonitor,PerformanceMonitorSystem.EnumHelper<T>,System.FormatUtils,System.HexConverter
var asyncLock = new System.Threading.ReentrantAsyncLock(); var cts = new CancellationTokenSource(); // Synchronous section asyncLock.Acquire(() => { // do work safely, reentry allowed on the same flow }); // Asynchronous section await asyncLock.AcquireAsync(async () => { await DoAsyncWork(); }); // Avoid unintentionally flowing AsyncLocal into CT callbacks: using (ExecutionContext.SuppressFlow()) { cts.Token.Register(() => asyncLock.Acquire(() => { // safe callback body })); }
var lifetime = new System.AsyncLifetime() { ContinueOnCapturedContext = true }; lifetime.AddDisposable(new FileStream(path, FileMode.Open)); lifetime.AddAsync(async () => await FlushBuffersAsync()); await lifetime.DisposeAsync(); // disposes in the right order, async‐aware
Span<char> initial = stackalloc char[128]; var sb = new System.Text.ValueStringBuilder(initial); sb.Append("User: "); sb.Append(userName); sb.Append(", Items: "); sb.Append(itemCount); string result = sb.ToString(); // minimal allocations
public class Example { public static async Task Main() { int failed = 0; String[] urls = [ "www.adatum.com", "www.cohovineyard.com", "www.cohowinery.com", "www.northwindtraders.com", "www.contoso.com" ]; var tasks = new ValueListBuilder<ValueTask>(urls.Length); foreach (var value in urls) { var url = value; tasks.Append(new ValueTask(Task.Run(() => { var png = new Ping(); try { var reply = png.Send(url); if (reply.Status != IPStatus.Success) { Interlocked.Increment(ref failed); throw new TimeoutException("Unable to reach " + url + "."); } } catch (PingException) { Interlocked.Increment(ref failed); throw; } }))); } ValueTask t = ValueTask.WhenAll(tasks.ToArray()); try { await t; } catch { } if (t.IsCompletedSuccessfully) Console.WriteLine("All ping attempts succeeded."); else if (t.IsFaulted) Console.WriteLine("{0} ping attempts failed", failed); } }
public class Example { public static async Task Main() { int failed = 0; String[] urls = [ "www.adatum.com", "www.cohovineyard.com", "www.cohowinery.com", "www.northwindtraders.com", "www.contoso.com" ]; var tasks = new ValueListBuilder<ValueTask<PingReply>>(urls.Length); foreach (var value in urls) { var url = value; tasks.Append(new ValueTask<PingReply>(Task.Run(() => { var png = new Ping(); try { var reply = png.Send(url); if (reply.Status != IPStatus.Success) { Interlocked.Increment(ref failed); throw new TimeoutException("Unable to reach " + url + "."); } return reply; } catch (PingException) { Interlocked.Increment(ref failed); throw; } }))); } try { PingReply[] replies = await ValueTask.WhenAll(tasks.ToArray()); Console.WriteLine("{0} ping attempts succeeded:", replies.Length); for (int i = 0; i < replies.Length; i++) { var reply = replies[i]; Console.WriteLine($"Reply from {reply.Address}: bytes={reply.Buffer.Length} time={reply.RoundtripTime}ms TTL={reply.Options?.Ttl} [{urls[i]}]"); } } catch (AggregateException) { Console.WriteLine("{0} ping attempts failed", failed); } } }
Via NuGet:
dotnet add package NuExt.System
Or via Visual Studio:
- Go to
Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution.... - Search for
NuExt.System. - Click "Install".
- NuExt.Minimal.Mvvm
- NuExt.Minimal.Mvvm.SourceGenerator
- NuExt.Minimal.Behaviors.Wpf
- NuExt.Minimal.Mvvm.Wpf
- NuExt.Minimal.Mvvm.MahApps.Metro
- NuExt.System.Data
- NuExt.System.Data.SQLite
Some implementations are derived from the .NET Runtime (MIT). See LICENSE and source comments for attributions.
Issues and PRs are welcome. Keep changes minimal and performance-conscious.
MIT. See LICENSE.