Ploch.Common
Core .NET utility library providing extension methods, guard clauses, reflection helpers, pattern matching, and randomisation utilities for everyday development tasks.
Overview
Ploch.Common is the foundational library in the Ploch.Common suite. It targets both netstandard2.0 and net8.0, making it suitable for the widest possible range of .NET projects from legacy frameworks to the latest runtimes.
The library is organised into functional namespaces rather than a single flat API surface. Each namespace addresses a specific concern: string manipulation, collection operations, argument checking, reflection, path handling, pattern matching, and random value generation. These utilities reduce boilerplate and consolidate common patterns across codebases.
Callers should be aware that on .NET 7 and later, guard clause methods use CallerArgumentExpressionAttribute to capture parameter names automatically, removing the need to pass string literals. On .NET Standard 2.0 and .NET 6, parameter names must be supplied explicitly.
Installation
dotnet add package Ploch.Common
Key Types
Argument Checking (Ploch.Common.ArgumentChecking)
| Type |
Description |
Guard |
Static partial class providing extension-method guard clauses for validating method arguments and enforcing preconditions. |
Strings (Ploch.Common namespace)
| Type |
Description |
StringExtensions |
Extension methods for string: null/empty checks, base64 encoding, case-insensitive comparison, prefix replacement, numeric parsing, and substring containment. |
StringParsingExtensions |
Nullable-returning parse helpers: ParseToBool, ParseToInt32, ParseToInt64. |
StringBuilderExtensions |
Extension methods for StringBuilder. |
Strings |
Static constants and factory methods for common string fragments: Space, Dash, Underscore, Dot, plus Spaces(n), Dashes(n), etc. |
Chars |
Character constants mirroring Strings. |
Collections (Ploch.Common.Collections)
| Type |
Description |
EnumerableExtensions |
Extensions for IEnumerable<T>: ForEach, None, Join, JoinWithFinalSeparator, Shuffle, TakeRandom, If (conditional query), IsEmpty, IsNullOrEmpty, Second, ExceptItems, ValueIn, AreIntegersSequentialInOrder. |
CollectionExtensions |
Extensions for ICollection<T>: AddMany with configurable DuplicateHandling, Add (key/value pair), AddIfNotNull. |
QueryableExtensions |
If (conditional query) for IQueryable<T>, preserving composability with LINQ to Entities. |
ArrayExtensions |
Array-specific extension methods. |
DictionaryExtensions |
Dictionary-specific extension methods. |
DuplicateHandling |
Enum controlling behaviour when adding duplicates: Throw, Ignore, Overwrite. |
Value Membership (Ploch.Common)
| Type |
Description |
IsInExtensions |
In and NotIn extension methods for checking whether a value is a member of a set, with optional custom IComparer<T>. |
IfNullHelpers |
OrIfNull and OrIfNullOrEmpty for concise null-coalescing. Note: OrIfNullOrEmpty currently delegates to OrIfNull and only checks for null, not emptiness. |
Reflection (Ploch.Common.Reflection)
| Type |
Description |
TypeExtensions |
IsConcreteImplementation, IsImplementing, IsEnumerable, IsNullable, IsSimpleType, GetReadableTypeName. |
TypeLoader |
Fluent type-discovery engine: load types from assemblies matching base-type constraints, assembly name globs, and type name globs. |
TypeLoaderConfigurator / ITypeLoaderConfigurator |
Builder interface for configuring TypeLoader. |
ObjectReflectionExtensions |
GetFieldValue, GetFieldValues, GetMemberValues — access field and property values including non-public and static members. |
PropertyHelpers |
Utilities for working with PropertyInfo. |
ByValueObjectComparator / ByValueObjectComparer |
Reflection-based value-equality comparison for objects. |
ObjectHashCodeBuilder |
Builds GetHashCode implementations from object properties via reflection. |
AssemblyExtensions / AssemblyListBuilder |
Helpers for working with Assembly instances. |
LINQ and Expressions (Ploch.Common.Linq)
| Type |
Description |
ExpressionExtensions |
GetMemberName — extract a member or method name string from a strongly-typed lambda expression. GetProperty — retrieve an IOwnedPropertyInfo from a property selector expression. |
IOwnedPropertyInfo<TType, TProperty> / OwnedPropertyInfo<TType, TProperty> |
Combines PropertyInfo with the owning object instance. |
IO and Paths (Ploch.Common.IO)
| Type |
Description |
PathUtils |
GetDirectoryName, ToSafeFileName, NormalizePathWithTrailingSeparator, NormalizePathWithoutTrailingSeparator, GetRelativePath, WithExtension, GetFullPathWithoutExtension. Also exposed as extension method WithExtension on string. |
StreamExtensions |
Extension methods for Stream. |
CommandLineParser / CommandLineInfo |
Basic command-line argument parsing utilities. |
Pattern Matching (Ploch.Common.Matchers)
| Type |
Description |
IMatcher<T> |
Single-method interface bool IsMatch(T? value). |
IStringMatcher |
Specialisation of IMatcher<string>. |
GlobEvaluator |
Evaluates strings against include/exclude glob patterns using Microsoft.Extensions.FileSystemGlobbing.Matcher. Configurable null/empty match results and string comparison. |
RegexListEvaluator |
Evaluates strings against a list of regular expressions. |
PropertyMatcher |
Matches objects by reflected property values. |
GlobMatcherExtensions |
Extension helpers for configuring Matcher with include/exclude patterns. |
Randomisation (Ploch.Common.Randomizers)
| Type |
Description |
IRandomizer |
Base interface: GetRandomValue(min, max) and GetRandomValue(). |
IRandomizer<TValue> |
Generic variant returning typed values. |
IRangedRandomizer<TValue> |
Adds typed min/max overload. |
Randomizer |
Static factory: GetRandomizer<TValue>() and GetRandomizer(Type). Supports string, int, DateTime, DateTimeOffset, bool. |
StringRandomizer, IntRandomizer, DateTimeRandomizer, DateTimeOffsetRandomizer, BooleanRandomizer |
Concrete randomiser implementations. |
ThreadSafeRandom |
Thread-safe Random wrapper. |
Enumerations
| Type |
Description |
EnumHelper |
GetEnumEntries<TEnum>() and GetFlags<TEnum>() for iterating all values or active flags of an enum. |
EnumerationConverter |
Extension methods for converting strings and integers to enum values: ParseToEnum<TEnum>() (throws on failure), SafeParseToEnum<TEnum>() (returns null on failure), and integer overloads. |
Type Conversion (Ploch.Common.TypeConversion)
| Type |
Description |
ITypeConverter |
Core converter interface with Order, CanHandle(value, targetType), CanHandleSourceType, CanHandleTargetType, and ConvertValue. Lower Order values are tried first. |
ITypeConverter<TSourceType, TTargetType> |
Generic variant combining ISourceTypeConverter<TSourceType> and ITargetTypeConverter<TTargetType> with strongly-typed conversion methods. |
ISourceTypeConverter<TSourceType> |
Specialisation of ITypeConverter scoped to a single source type. |
ITargetTypeConverter<TTargetType> |
Specialisation of ITypeConverter scoped to a single target type, with ConvertValueToTargetType. |
TypeConverter |
Abstract base class implementing ITypeConverter with configurable null handling, supported source/target type collections, and ordering. |
SingleSourceTargetTypeConverter<TSource, TTarget> |
Abstract base for converters between a single source and target type pair, with support for derived-type handling and null source values. |
ObjectConverter |
Static class that builds typed objects from ISourceObject property bags using an ordered converter pipeline. |
ObjectPropertyAttribute |
Attribute for remapping a source property name to a differently-named target property during object conversion. |
EnumConverter |
Converts string values to nullable enum types using a field-name mapping cache (EnumerationFieldValueCache). |
TypeConversionException |
Exception thrown when a type conversion fails. |
TypeConverterHelper |
Static helper methods for type compatibility checks and combining type sets. |
Date and Time
| Type |
Description |
DateTimeExtensions |
ToEpochSeconds, ToDateTime (from epoch seconds, with automatic millis detection), nullable overloads. |
DateTimeFormats |
Common format string constants. |
Cryptography (Ploch.Common.Cryptography)
| Type |
Description |
Hashing |
ToHashString(HashAlgorithm) and ToMD5HashString() extension methods on Stream. |
Enum Parsing (Ploch.Common)
| Type |
Description |
EnumerationConverter |
Static class with ParseToEnum<TEnum>(string), ParseToEnum<TEnum>(int), SafeParseToEnum<TEnum>(string?), and SafeParseToEnum<TEnum>(int?) extension methods for type-safe enum conversion. |
Other Utilities
| Type |
Description |
StopwatchUtil |
Convenience methods for timing code execution. |
ComparisonUtils |
Generic comparison helpers. |
ContentSizes |
Constants for common content size thresholds. |
ObjectCloningHelpers |
Deep-clone utilities. |
OperatingSystemExtensions |
Extensions on OperatingSystem. |
EnvironmentUtilities / EnvironmentVariables |
Helpers for reading environment state: GetCurrentAppPath(), GetEnvironmentCommandLine(), GetString(name), GetBool(name), GetEnumValue<TEnum>(name). |
AssemblyInformation / AssemblyInformationProvider |
Reads version and metadata from assemblies. |
Usage Examples
Guard Clauses
using Ploch.Common.ArgumentChecking;
public void Process(string name, IEnumerable<int> items, MyEnum status)
{
// Throws ArgumentNullException if null; ArgumentException if empty
name.NotNullOrEmpty();
// Throws ArgumentNullException if null
var safeItems = items.NotNull();
// Throws ArgumentOutOfRangeException if value is not defined in the enum
status.NotOutOfRange();
// Throws ArgumentOutOfRangeException if value is not positive
var count = items.Count();
count.Positive();
}
// RequiredNotNull throws InvalidOperationException (used for state checks, not argument checks)
var config = _configuration.RequiredNotNull();
String Extensions
using Ploch.Common;
// Null/empty checks as extension methods
string? input = GetInput();
if (input.IsNullOrEmpty()) return;
if (input.IsNullOrWhiteSpace()) return;
// Returns null if empty, enabling null-conditional chaining
var normalised = input.NullIfEmpty();
// Case-insensitive comparison
if (input.EqualsIgnoreCase("admin")) { }
// Contains any of a set of substrings
if (input.ContainsAny("error", "fail", "exception")) { }
if (input.ContainsAny(StringComparison.OrdinalIgnoreCase, "Error", "FAIL")) { }
// Base64 encoding/decoding
var encoded = "hello world".ToBase64String();
var decoded = encoded.FromBase64String();
// Numeric parsing
int value = "42".ToInt32();
if ("99".TryConvertToInt32(out var n)) { }
Collection Extensions
using Ploch.Common.Collections;
var items = new List<string> { "a", "b", "c" };
// Side-effect iteration returning the same enumerable (fluent)
items.ForEach(Console.WriteLine);
// Inverse of Any
bool hasNoErrors = items.None(x => x.StartsWith("err"));
// Join with separator
string result = items.Join(", "); // "a, b, c"
string natural = items.JoinWithFinalSeparator(", ", " and "); // "a, b and c"
// Conditional query composition (useful for optional filters)
var query = GetCars()
.OrderBy(x => x.Created)
.If(createdAfter.HasValue, x => x.Where(y => y.Created > createdAfter!.Value))
.If(first.HasValue, x => x.Take(first!.Value));
// Shuffle and random sampling
var shuffled = items.Shuffle();
var sample = items.TakeRandom(2);
// Null/empty check
if (items.IsNullOrEmpty()) { }
// Collection membership with AddMany
var set = new HashSet<string>();
set.AddMany(new[] { "x", "y" }, DuplicateHandling.Ignore);
Value Membership
using Ploch.Common;
// In / NotIn - readable membership check
var day = DayOfWeek.Saturday;
if (day.In(DayOfWeek.Saturday, DayOfWeek.Sunday))
{
Console.WriteLine("Weekend");
}
string status = "active";
if (status.NotIn("archived", "deleted")) { }
Reflection and Type Discovery
using Ploch.Common.Reflection;
// Type checks
typeof(MyService).IsConcreteImplementation<IMyService>(); // true
typeof(string).IsSimpleType(); // true
typeof(List<int>).IsEnumerable(); // true
typeof(List<string>).GetReadableTypeName(); // "List<String>"
// TypeLoader — discover all concrete IHandler implementations in two assemblies
var loader = TypeLoader.Configure(cfg => cfg
.WithBaseType<IHandler>()
.WithAssemblyGlob(m => m.AddInclude("MyApp.*")));
loader.LoadTypes(typeof(MyApp.Startup))
.LoadTypes(typeof(MyPlugin.Entry));
foreach (var handlerType in loader.LoadedTypes)
{
Console.WriteLine(handlerType.FullName);
}
Path Utilities
using Ploch.Common.IO;
// Normalise paths
string withSep = PathUtils.NormalizePathWithTrailingSeparator(@"C:\projects\myapp");
// "C:\projects\myapp\"
// Safe file name (replaces illegal characters with '_')
string safe = PathUtils.ToSafeFileName("Report: Q1/2024.xlsx");
// "Report_ Q1_2024.xlsx"
// File extension manipulation
string newPath = "/data/report.txt".WithExtension(".md");
// "/data/report.md"
string relPath = PathUtils.GetRelativePath(@"C:\base\", @"C:\base\sub\file.txt");
// "sub\file.txt"
Pattern Matching
using Ploch.Common.Matchers;
// Glob-based string matching with include/exclude patterns
var evaluator = new GlobEvaluator(
includes: new[] { "**/*.cs" },
excludes: new[] { "**/obj/**", "**/bin/**" });
evaluator.IsMatch("src/MyProject/Class.cs"); // true
evaluator.IsMatch("src/MyProject/obj/Temp.cs"); // false
Randomisers
using Ploch.Common.Randomizers;
var intRandomizer = Randomizer.GetRandomizer<int>();
int value = intRandomizer.GetRandomValue(1, 100);
var dateRandomizer = Randomizer.GetRandomizer<DateTime>();
DateTime date = dateRandomizer.GetRandomValue(DateTime.Today.AddYears(-1), DateTime.Today);
Date/Time
using Ploch.Common;
long epochSeconds = DateTime.UtcNow.ToEpochSeconds();
DateTime restored = epochSeconds.ToDateTime();
// Handles both epoch seconds and epoch milliseconds automatically
DateTime fromMillis = 1700000000000L.ToDateTime();
Enum Parsing
using Ploch.Common;
public enum Status { Active, Inactive, Pending }
// Parse string to enum (throws on failure)
Status status = "Active".ParseToEnum<Status>();
Status caseInsensitive = "active".ParseToEnum<Status>(ignoreCase: true);
// Parse int to enum
Status fromInt = 1.ParseToEnum<Status>();
// Safe parse — returns null instead of throwing
Status? maybe = "Unknown".SafeParseToEnum<Status>(); // null
Status? valid = "Pending".SafeParseToEnum<Status>(); // Status.Pending
Cryptography / Hashing
using Ploch.Common.Cryptography;
using System.Security.Cryptography;
using var stream = File.OpenRead("data.bin");
// Compute an MD5 hash string
string md5 = stream.ToMD5HashString();
// Use any HashAlgorithm
stream.Position = 0;
string sha256 = stream.ToHashString(SHA256.Create());
Environment Utilities
using Ploch.Common;
// Read typed environment variables
string? apiKey = EnvironmentVariables.GetString("API_KEY");
bool? debug = EnvironmentVariables.GetBool("DEBUG_MODE");
Status? envStatus = EnvironmentVariables.GetEnumValue<Status>("APP_STATUS");
// Get the current application path
string appPath = EnvironmentUtilities.GetCurrentAppPath();