Eventualist.Extensions 5.0.3

dotnet add package Eventualist.Extensions --version 5.0.3
                    
NuGet\Install-Package Eventualist.Extensions -Version 5.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Eventualist.Extensions" Version="5.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Eventualist.Extensions" Version="5.0.3" />
                    
Directory.Packages.props
<PackageReference Include="Eventualist.Extensions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Eventualist.Extensions --version 5.0.3
                    
#r "nuget: Eventualist.Extensions, 5.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Eventualist.Extensions@5.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Eventualist.Extensions&version=5.0.3
                    
Install as a Cake Addin
#tool nuget:?package=Eventualist.Extensions&version=5.0.3
                    
Install as a Cake Tool

Eventualist.Extensions

.NET License: MIT

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 value
    false.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 empty
  • IsNotEmpty<T>() - Returns true if the collection contains any elements
  • WhereNotNull<T>() - Filters out null values from a collection
    var 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 items
    var numbers = new[] { 1, 2, 3, 4, 5 };
    numbers.ContainsAll(2, 4) // Returns true
    numbers.ContainsAll(2, 6) // Returns false
    
  • Divide<T>(int maxLength) - Splits a collection into sublists with a specified maximum length
    var 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 odd
    4.IsEven() // Returns true
    5.IsOdd() // Returns true
    
  • IsBetween(min, max) - Determines whether a number is between two values (inclusive)
    5.IsBetween(1, 10) // Returns true
    15.IsBetween(1, 10) // Returns false
    
  • Clamp(min, max) - Clamps a number to be within a specified range
    15.Clamp(0, 10) // Returns 10
    (-5).Clamp(0, 10) // Returns 0
    5.Clamp(0, 10) // Returns 5
    
  • ToOrdinal() - Converts a number to its ordinal string representation
    1.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 true
    
  • ConvertToMimeType() - 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 empty
    string? 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 date
    var birthdate = new DateTime(1990, 1, 1);
    var age = birthdate.Age(); // Returns the current age
    
  • ToRelativeTime() / ToRelativeTime(DateTime referenceDate) - Returns a human-readable relative time string
    var pastDate = DateTime.Now.AddHours(-2);
    pastDate.ToRelativeTime() // Returns "2 hours ago"
    
  • IsToday() / IsTomorrow() / IsYesterday() - Determines whether the date is today, tomorrow, or yesterday
    DateTime.Today.IsToday() // Returns true
    DateTime.Today.AddDays(1).IsTomorrow() // Returns true
    
  • StartOfWeek(DayOfWeek startOfWeek = DayOfWeek.Sunday) / EndOfWeek(DayOfWeek startOfWeek = DayOfWeek.Sunday) - Returns the start or end of the week
    var 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.999
    
  • MustComeBefore Attribute - Validation attribute to ensure one DateTime property precedes another
    public class TimePeriod
    {
        [MustComeBefore("EndDate")]
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
    }
    

Function Memoization

  • Memoize() - Automatically caches function results for improved performance
    Func<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 null

    string? 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 null

    string? 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, use text.IsNull<string>() instead of text.IsNull() when the compiler cannot infer the type.
    • Fixed CallerArgumentExpression in ThrowIfNull to correctly capture parameter names
  • 5.0.0.1: Major upgrade to .NET 10.0 and C# 14
    • Refactored all extension methods to use modern extension syntax 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 MustComeBefore attributes 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
  • 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:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes and add tests
  4. Run dotnet test locally to ensure all tests pass
  5. 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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