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‑awareSpan<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 allocationspublic 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.SystemOr 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.Wpf
- NuExt.Minimal.Mvvm.MahApps.Metro
- NuExt.System.Data
- NuExt.System.Data.SQLite
- NuExt.DevExpress.Mvvm
- NuExt.DevExpress.Mvvm.MahApps.Metro
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.