Eventualist.Extensions
5.0.3
dotnet add package Eventualist.Extensions --version 5.0.3
NuGet\Install-Package Eventualist.Extensions -Version 5.0.3
<PackageReference Include="Eventualist.Extensions" Version="5.0.3" />
<PackageVersion Include="Eventualist.Extensions" Version="5.0.3" />
<PackageReference Include="Eventualist.Extensions" />
paket add Eventualist.Extensions --version 5.0.3
#r "nuget: Eventualist.Extensions, 5.0.3"
#:package Eventualist.Extensions@5.0.3
#addin nuget:?package=Eventualist.Extensions&version=5.0.3
#tool nuget:?package=Eventualist.Extensions&version=5.0.3
Eventualist.Extensions
A collection of lightweight, focused extension methods for common .NET types. Originally created for personal projects but available for anyone to use.
⚠️ Disclaimer
This library is primarily developed for personal use and experimentation. While it is publicly available and contributions are welcome, please note:
- No Warranty: This software is provided "as is", without warranty of any kind, express or implied
- Use at Your Own Risk: The library may contain bugs or incomplete features
- Breaking Changes: API changes may occur between versions without extensive deprecation notices
- Limited Support: Support and maintenance are provided on a best-effort basis
- Experimental Features: Some features may be experimental, especially those targeting preview versions of .NET
For production use, please thoroughly test the library in your specific context and consider pinning to a specific version.
Features
Boolean Extensions
AddNot(string text, string negation = "not ")- Conditionally prefixes a string with a negation word based on the boolean valuefalse.AddNot("implemented") // Returns "not implemented" true.AddNot("implemented") // Returns "implemented"ToYesOrNo(string yes = "yes", string no = "no", string unknown = "unknown")- Converts boolean to yes/no strings (supports nullable booleans)true.ToYesOrNo() // Returns "yes" false.ToYesOrNo() // Returns "no" ((bool?)null).ToYesOrNo() // Returns "unknown"
Collection Extensions
IsEmpty<T>()- Returns true if the collection is emptyIsNotEmpty<T>()- Returns true if the collection contains any elementsWhereNotNull<T>()- Filters out null values from a collectionvar items = new[] { "a", null, "b", null, "c" }; var filtered = items.WhereNotNull(); // Returns ["a", "b", "c"]ContainsAll<T>(params T[] items)- Determines whether the collection contains all of the specified itemsvar numbers = new[] { 1, 2, 3, 4, 5 }; numbers.ContainsAll(2, 4) // Returns true numbers.ContainsAll(2, 6) // Returns falseDivide<T>(int maxLength)- Splits a collection into sublists with a specified maximum lengthvar numbers = new[] { 1, 2, 3, 4, 5, 6, 7 }; var chunks = numbers.Divide(3); // Returns [[1,2,3], [4,5,6], [7]]
Numeric Extensions
IsEven()/IsOdd()- Determines whether a number is even or odd4.IsEven() // Returns true 5.IsOdd() // Returns trueIsBetween(min, max)- Determines whether a number is between two values (inclusive)5.IsBetween(1, 10) // Returns true 15.IsBetween(1, 10) // Returns falseClamp(min, max)- Clamps a number to be within a specified range15.Clamp(0, 10) // Returns 10 (-5).Clamp(0, 10) // Returns 0 5.Clamp(0, 10) // Returns 5ToOrdinal()- Converts a number to its ordinal string representation1.ToOrdinal() // Returns "1st" 2.ToOrdinal() // Returns "2nd" 3.ToOrdinal() // Returns "3rd" 21.ToOrdinal() // Returns "21st"
String Extensions
Titleize()- Converts a string to title case"helloWorld".Titleize() // Returns "Hello World" "SHOUTING_TEXT".Titleize() // Returns "Shouting_TEXT" "snake_case_example".Titleize() // Returns "Snake_case_example"ToSlug()- Converts a string to a URL-friendly slug"Hello World!".ToSlug() // Returns "hello-world" "C# Programming 101".ToSlug() // Returns "c-programming-101"RemoveWhitespace()- Removes all whitespace characters from a string"Hello World".RemoveWhitespace() // Returns "HelloWorld" " spaces everywhere ".RemoveWhitespace() // Returns "spaceseverywhere"Abbreviate(int maxLength, string abbreviationSymbol = "...")- Shortens a string to a maximum length with ellipsis"This is a very long sentence that needs to be abbreviated".Abbreviate(30) // Returns "This is a very long..." "Short text".Abbreviate(20) // Returns "Short text" (no truncation needed)Truncate(int maxLength, string suffix = "...")- Truncates a string to a maximum length"Hello World".Truncate(8) // Returns "Hello..." "Hello World".Truncate(8, "[more]") // Returns "Hel[more]"StripHtml()- Removes HTML tags from a string"<p>Hello <strong>World</strong></p>".StripHtml() // Returns "Hello World"HasCorrectExtension(params string[] additionalExtensions)- Validates file extension (defaults to image extensions)"photo.jpg".HasCorrectExtension() // Returns true "document.pdf".HasCorrectExtension() // Returns false "document.pdf".HasCorrectExtension("pdf", "doc") // Returns trueConvertToMimeType()- Converts file extension to MIME type"jpg".ConvertToMimeType() // Returns "image/jpeg" ".png".ConvertToMimeType() // Returns "image/png" "pdf".ConvertToMimeType() // Returns "application/pdf" "unknown".ConvertToMimeType() // Returns "application/octet-stream"ShowIfNone(string alternativeText = "None")- Returns alternative text if string is null or emptystring? emptyString = null; emptyString.ShowIfNone() // Returns "None" emptyString.ShowIfNone("N/A") // Returns "N/A" "Hello".ShowIfNone() // Returns "Hello"ToSentenceCase()- Converts camelCase or PascalCase to sentence case"thisIsATest".ToSentenceCase() // Returns "this is a test" "PascalCaseExample".ToSentenceCase() // Returns "pascal case example"SplitCamelCase()- Splits camel case text into separate words"camelCaseString".SplitCamelCase() // Returns "camel Case String" "HTTPSConnection".SplitCamelCase() // Returns "HTTPS Connection"Capitalize(CultureInfo? culture = null)- Capitalizes the first character"hello".Capitalize() // Returns "Hello"Left(int length)/Right(int length)- Gets leftmost or rightmost characters"Hello World".Left(5) // Returns "Hello" "Hello World".Right(5) // Returns "World"Reverse()- Reverses a string"Hello".Reverse() // Returns "olleH"ParseDateFromDateTimePicker(CultureInfo? culture = null)- Parses yyyy/MM/dd format dates"2024/12/25".ParseDateFromDateTimePicker() // Returns DateTime(2024, 12, 25) "invalid".ParseDateFromDateTimePicker() // Returns null
DateTime Extensions & Validation
Age()/Age(DateTime asOfDate)- Calculates the age in years from this datevar birthdate = new DateTime(1990, 1, 1); var age = birthdate.Age(); // Returns the current ageToRelativeTime()/ToRelativeTime(DateTime referenceDate)- Returns a human-readable relative time stringvar pastDate = DateTime.Now.AddHours(-2); pastDate.ToRelativeTime() // Returns "2 hours ago"IsToday()/IsTomorrow()/IsYesterday()- Determines whether the date is today, tomorrow, or yesterdayDateTime.Today.IsToday() // Returns true DateTime.Today.AddDays(1).IsTomorrow() // Returns trueStartOfWeek(DayOfWeek startOfWeek = DayOfWeek.Sunday)/EndOfWeek(DayOfWeek startOfWeek = DayOfWeek.Sunday)- Returns the start or end of the weekvar date = new DateTime(2024, 1, 10); // Wednesday date.StartOfWeek(DayOfWeek.Monday) // Returns Monday of that week date.EndOfWeek(DayOfWeek.Monday) // Returns Sunday at 23:59:59.999MustComeBeforeAttribute - Validation attribute to ensure one DateTime property precedes anotherpublic class TimePeriod { [MustComeBefore("EndDate")] public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } }
Function Memoization
Memoize()- Automatically caches function results for improved performanceFunc<int, int> expensiveOperation = x => { /* ... */ }; var memoized = expensiveOperation.Memoize(); // First call computes and caches result var result1 = memoized(5); // Subsequent calls with same input return cached result var result2 = memoized(5); // Instant return from cache- Supports functions with up to two arguments
- Note: Not optimized for recursive functions
Object Extensions
IsNull<T>()/IsNotNull<T>()- Determines whether an object is null or not nullstring? text = null; text.IsNull<string>() // Returns true "hello".IsNotNull<string>() // Returns true⚠️ Note (v5.0.2.0+): Due to the migration to C# 14 extension syntax, the type parameter may need to be explicitly specified in some contexts where type inference is ambiguous.
ThrowIfNull<T>()- Throws an ArgumentNullException if the object is nullstring? text = GetText(); text.ThrowIfNull<string>(); // Throws if text is null, otherwise returns text var upper = text.ThrowIfNull<string>().ToUpper(); // Method chaining⚠️ Note (v5.0.2.0+): The type parameter may need to be explicitly specified in some contexts. The method also supports an overload with a custom error message:
text.ThrowIfNull<string>("Text cannot be null");
ExtendedDictionary
- Thread-safe dictionary implementation with improved performance characteristics
Installation
Add the package reference to your project:
<PackageReference Include="Eventualist.Extensions" Version="5.0.0.1" />
Or via the .NET CLI:
dotnet add package Eventualist.Extensions
Compatibility
- Target Frameworks: .NET 8.0 (net8.0), .NET 9.0 (net9.0), .NET 10.0 (net10.0)
- C# Language Version: 14.0
- License: MIT
The NuGet package includes separate assemblies for each supported framework, allowing you to use it in projects targeting .NET 8, .NET 9, or .NET 10.
Version History
- 5.0.2.0: Multi-framework support and compatibility improvements
- Added support for .NET 8.0 and .NET 9.0 (in addition to .NET 10.0)
- Package now includes assemblies for net8.0, net9.0, and net10.0
- Breaking Change: Object extension methods (
IsNull<T>(),IsNotNull<T>(),ThrowIfNull<T>()) may require explicit type parameters in some contexts due to C# 14 extension syntax migration. For example, usetext.IsNull<string>()instead oftext.IsNull()when the compiler cannot infer the type. - Fixed
CallerArgumentExpressioninThrowIfNullto correctly capture parameter names
- 5.0.0.1: Major upgrade to .NET 10.0 and C# 14
- Refactored all extension methods to use modern
extensionsyntax for improved readability - Enhanced Boolean, Collection, DateTime, Function, and String extensions with better null handling
- Improved XML documentation across all methods
- Consolidated nullable and non-nullable overloads where applicable
- Updated dependencies to latest versions
- Added support for multiple
MustComeBeforeattributes on a single property - Optimized string truncation logic for better clarity
- Code cleanup and modernization following C# 14 conventions
- Improved testability and backward compatibility
- Streamlined CI/CD workflow with strong-name key provisioning
- Refactored all extension methods to use modern
- 4.0.0.3-dev0004: Updated to .NET 10 and C# 14, refreshed CI workflow
- 3.x: Updates for .NET 9 compatibility
- 2.0.0.0: .NET 6.0 compatibility (use version 1.0.0.19 for older frameworks)
- 1.0.0.13: Added Memoize functionality
- 1.0.0.0: Initial release with Bool and Collection extensions
Building and Testing
The project includes a GitHub Actions CI workflow (.github/workflows/dotnet.yml) that automatically:
- Restores NuGet packages
- Builds the solution using .NET 10 SDK
- Runs all unit tests
Local Development
# Restore dependencies
dotnet restore
# Build the solution
dotnet build
# Run tests
dotnet test
# Create NuGet package
dotnet pack
Contributing
Contributions are welcome! Please see our Contributing Guidelines for detailed information on how to contribute.
Quick start:
- Fork the repository
- Create a feature branch
- Make your changes and add tests
- Run
dotnet testlocally to ensure all tests pass - Submit a pull request
For bug reports, feature requests, or questions, please open an issue on GitHub.
Security
For information about reporting security vulnerabilities and our security policies, please see our Security Policy.
Important: Do not report security vulnerabilities through public GitHub issues. Please email info@esoxsolutions.nl instead.
Author
Iede Snoek
Email: info@esoxsolutions.nl
Company: Esox Solutions
License
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2022-2025 Esox Solutions
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.0.3 | 31 | 2/27/2026 |
| 5.0.2 | 433 | 12/10/2025 |
| 5.0.1 | 423 | 12/10/2025 |
| 5.0.0.1 | 191 | 11/15/2025 |
| 4.0.0.4 | 227 | 6/5/2025 |
| 3.0.0.17 | 369 | 11/25/2023 |
| 3.0.0.9 | 191 | 11/25/2023 |
| 2.0.0.17 | 361 | 3/5/2023 |
| 2.0.0.15 | 411 | 1/29/2023 |
| 2.0.0.11 | 536 | 9/3/2022 |
| 2.0.0.9 | 568 | 7/14/2022 |
| 2.0.0.1 | 566 | 7/14/2022 |
| 1.0.0.19 | 716 | 1/4/2021 |