Klab.Toolkit.ExtensionMethods 2.11.0

dotnet add package Klab.Toolkit.ExtensionMethods --version 2.11.0
                    
NuGet\Install-Package Klab.Toolkit.ExtensionMethods -Version 2.11.0
                    
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="Klab.Toolkit.ExtensionMethods" Version="2.11.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Klab.Toolkit.ExtensionMethods" Version="2.11.0" />
                    
Directory.Packages.props
<PackageReference Include="Klab.Toolkit.ExtensionMethods" />
                    
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 Klab.Toolkit.ExtensionMethods --version 2.11.0
                    
#r "nuget: Klab.Toolkit.ExtensionMethods, 2.11.0"
                    
#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 Klab.Toolkit.ExtensionMethods@2.11.0
                    
#: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=Klab.Toolkit.ExtensionMethods&version=2.11.0
                    
Install as a Cake Addin
#tool nuget:?package=Klab.Toolkit.ExtensionMethods&version=2.11.0
                    
Install as a Cake Tool

Klab.Toolkit.ExtensionMethods

Overview

The Klab.Toolkit.ExtensionMethods package provides a comprehensive collection of extension methods that enhance built-in .NET types with frequently needed functionality. These extensions promote cleaner, more readable code while reducing boilerplate and improving developer productivity.

Purpose

This package extends common .NET types with practical functionality:

  • String Operations: Case conversions, validation, formatting, and parsing
  • Enum Utilities: Description handling, reflection-based operations, and metadata extraction
  • Type Inspection: Generic type analysis, interface checking, and reflection helpers
  • Validation: Built-in validation for common patterns (email, phone, etc.)

Key Features

String Extensions

  • Case conversion methods (PascalCase, camelCase, kebab-case, etc.)
  • Validation methods for emails, phone numbers, URLs
  • HTML manipulation and sanitization
  • String parsing and formatting utilities

Enum Extensions

  • Description attribute extraction
  • Enum-to-dictionary conversions
  • Metadata operations for enum types

Type Extensions

  • Generic type analysis
  • Interface compatibility checking
  • Reflection utilities for type inspection

Installation

dotnet add package Klab.Toolkit.ExtensionMethods

String Extensions

String Validation

// Email validation
string email = "user@example.com";
bool isValidEmail = email.IsValidEmail(); // true

string invalidEmail = "not-an-email";
bool isInvalid = invalidEmail.IsValidEmail(); // false

// Phone number validation
string phone = "+1 (555) 123-4567";
bool isValidPhone = phone.IsValidPhoneNumber(); // true

// URL validation
string url = "https://www.example.com";
bool isValidUrl = url.IsValidUrl(); // true

// Check if string contains only letters
string letters = "HelloWorld";
bool onlyLetters = letters.ContainsOnlyLetters(); // true

string mixed = "Hello123";
bool mixedCheck = mixed.ContainsOnlyLetters(); // false

HTML and Content Manipulation

// Remove HTML tags
string htmlContent = "<p>Hello <strong>World</strong>!</p>";
string plainText = htmlContent.RemoveHtmlTags(); // "Hello World!"

// Remove HTML comments
string htmlWithComments = "<p>Content</p>";
string cleaned = htmlWithComments.RemoveHtmlComments(); // "<p>Content</p>"

// Remove scripts and styles
string htmlWithScript = "<p>Content</p><script>alert('xss')</script>";
string safe = htmlWithScript.RemoveHtmlScripts(); // "<p>Content</p>"

// URL decoding
string encoded = "Hello%20World%21";
string decoded = encoded.UrlDecode(); // "Hello World!"

String Utilities

// Null/whitespace checking
string empty = "";
string whitespace = "   ";
string content = "Hello";

bool isEmpty1 = empty.IsNullOrWhiteSpace(); // true
bool isEmpty2 = whitespace.IsNullOrWhiteSpace(); // true
bool isEmpty3 = content.IsNullOrWhiteSpace(); // false

// Truncation with ellipsis
string longText = "This is a very long text that needs to be truncated";
string truncated = longText.Truncate(20); // "This is a very long..."

// Safe substring
string text = "Hello World";
string safe1 = text.SafeSubstring(0, 5); // "Hello"
string safe2 = text.SafeSubstring(0, 100); // "Hello World" (no exception)

// Reverse string
string original = "Hello";
string reversed = original.Reverse(); // "olleH"

Practical Examples

public class UserRegistrationService
{
    public Result<User> ValidateAndCreateUser(string email, string phone, string name)
    {
        // Validate email
        if (!email.IsValidEmail())
        {
            return Error.Create("INVALID_EMAIL", "Please provide a valid email address");
        }

        // Validate phone (optional)
        if (!string.IsNullOrWhiteSpace(phone) && !phone.IsValidPhoneNumber())
        {
            return Error.Create("INVALID_PHONE", "Please provide a valid phone number");
        }

        // Clean and format name
        var cleanName = name.RemoveHtmlTags().Trim();
        if (cleanName.IsNullOrWhiteSpace())
        {
            return Error.Create("INVALID_NAME", "Name is required");
        }

        var user = new User
        {
            Email = email.ToLowerInvariant(),
            Phone = phone,
            DisplayName = cleanName.ToTitleCase(),
            Username = cleanName.ToCamelCase()
        };

        return Result.Success(user);
    }
}

public class ContentService
{
    public string SanitizeUserContent(string userInput)
    {
        return userInput
            .RemoveHtmlTags()
            .RemoveHtmlComments()
            .RemoveHtmlScripts()
            .Trim();
    }

    public string CreateSlug(string title)
    {
        return title
            .ToLowerInvariant()
            .RemoveHtmlTags()
            .ToKebabCase()
            .Truncate(50);
    }
}

Enum Extensions

Description Attribute Handling

using System.ComponentModel;

// Define enum with descriptions
public enum OrderStatus
{
    [Description("Order is pending approval")]
    Pending,

    [Description("Order has been approved and is being processed")]
    Processing,

    [Description("Order has been shipped to customer")]
    Shipped,

    [Description("Order has been delivered successfully")]
    Delivered,

    [Description("Order has been cancelled")]
    Cancelled
}

// Usage
OrderStatus status = OrderStatus.Processing;
string description = status.GetDescription();
// "Order has been approved and is being processed"

// Without description attribute
OrderStatus pending = OrderStatus.Pending;
string defaultDesc = pending.GetDescription(); // "Pending"

Enum Metadata Operations

// Get all enum values with descriptions as dictionary
Dictionary<string, string> statusDescriptions =
    EnumExtensions.GetDictionaryWithEnumNameAndDescription<OrderStatus>();

// Results in:
// {
//   "Pending": "Order is pending approval",
//   "Processing": "Order has been approved and is being processed",
//   "Shipped": "Order has been shipped to customer",
//   "Delivered": "Order has been delivered successfully",
//   "Cancelled": "Order has been cancelled"
// }

// Use in dropdowns or UI
public class OrderController : ControllerBase
{
    [HttpGet("statuses")]
    public IActionResult GetOrderStatuses()
    {
        var statuses = EnumExtensions.GetDictionaryWithEnumNameAndDescription<OrderStatus>()
            .Select(kvp => new { Value = kvp.Key, Text = kvp.Value })
            .ToList();

        return Ok(statuses);
    }
}

Advanced Enum Usage

public enum Priority
{
    [Description("Low priority - can be handled later")]
    Low = 1,

    [Description("Normal priority - standard processing")]
    Normal = 2,

    [Description("High priority - expedited processing")]
    High = 3,

    [Description("Critical priority - immediate attention required")]
    Critical = 4
}

public class TaskService
{
    public string GetPriorityDisplayText(Priority priority)
    {
        return priority.GetDescription();
    }

    public Dictionary<string, string> GetAllPriorities()
    {
        return EnumExtensions.GetDictionaryWithEnumNameAndDescription<Priority>();
    }

    public IEnumerable<SelectListItem> GetPrioritySelectItems()
    {
        return EnumExtensions.GetDictionaryWithEnumNameAndDescription<Priority>()
            .Select(kvp => new SelectListItem
            {
                Value = kvp.Key,
                Text = kvp.Value
            });
    }
}

// Usage in validation
public class CreateTaskRequest
{
    public string Title { get; set; }
    public Priority Priority { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!Enum.IsDefined(typeof(Priority), Priority))
        {
            yield return new ValidationResult(
                $"Invalid priority. Valid values are: {string.Join(", ", EnumExtensions.GetDictionaryWithEnumNameAndDescription<Priority>().Keys)}",
                new[] { nameof(Priority) }
            );
        }
    }
}

Type Extensions

Generic Type Analysis

using Klab.Toolkit.Common.Extensions;

// Check if type can be cast to another
Type stringType = typeof(string);
Type objectType = typeof(object);
bool canCast = stringType.CanBeCastTo(objectType); // true

// Generic type compatibility
Type openGeneric = typeof(List<>);
Type closedGeneric = typeof(List<string>);
bool couldClose = openGeneric.CouldCloseTo(closedGeneric); // true

// Find interfaces that close to a template
Type concreteType = typeof(List<string>);
Type templateInterface = typeof(IEnumerable<>);
var interfaces = concreteType.FindInterfacesThatClose(templateInterface);
// Returns interfaces like IEnumerable<string>

Practical Type Inspection

public class ServiceRegistrationHelper
{
    public static void RegisterHandlers(IServiceCollection services, Assembly assembly)
    {
        var handlerInterface = typeof(IRequestHandler<,>);

        var handlerTypes = assembly.GetTypes()
            .Where(type => type.IsClass && !type.IsAbstract)
            .Where(type => type.GetInterfaces()
                .Any(i => i.IsGenericType &&
                         i.GetGenericTypeDefinition().CanBeCastTo(handlerInterface)))
            .ToList();

        foreach (var handlerType in handlerTypes)
        {
            var interfaces = handlerType.FindInterfacesThatClose(handlerInterface);
            foreach (var interfaceType in interfaces)
            {
                services.AddTransient(interfaceType, handlerType);
            }
        }
    }
}

public class TypeValidator
{
    public static bool IsValidServiceType(Type type)
    {
        // Check if type can be cast to required interface
        return type.CanBeCastTo(typeof(IDisposable)) ||
               type.GetInterfaces().Any(i => i.Name.EndsWith("Service"));
    }

    public static IEnumerable<Type> FindImplementations<T>(Assembly assembly)
    {
        var targetType = typeof(T);
        return assembly.GetTypes()
            .Where(type => type.IsClass &&
                          !type.IsAbstract &&
                          type.CanBeCastTo(targetType));
    }
}

Real-World Integration Examples

API Response Formatting

public class ApiResponseService
{
    public object FormatErrorResponse(string errorCode, string errorMessage)
    {
        return new
        {
            Error = new
            {
                Code = errorCode.ToUpperInvariant(),
                Message = errorMessage.RemoveHtmlTags(),
                Timestamp = DateTime.UtcNow
            }
        };
    }

    public string GenerateSlugFromTitle(string title)
    {
        return title
            .RemoveHtmlTags()
            .ToLowerInvariant()
            .ToKebabCase()
            .Truncate(50);
    }
}

Configuration Processing

public class ConfigurationProcessor
{
    public Dictionary<string, object> ProcessEnvironmentVariables()
    {
        var config = new Dictionary<string, object>();

        foreach (DictionaryEntry env in Environment.GetEnvironmentVariables())
        {
            var key = env.Key.ToString();
            var value = env.Value?.ToString() ?? "";

            // Convert environment variable names to camelCase
            var camelKey = key.ToLowerInvariant().ToCamelCase();

            // Clean and validate values
            if (!value.IsNullOrWhiteSpace())
            {
                // Check if it's an email
                if (value.IsValidEmail())
                {
                    config[camelKey] = value.ToLowerInvariant();
                }
                // Check if it's a URL
                else if (value.IsValidUrl())
                {
                    config[camelKey] = value;
                }
                // Regular string value
                else
                {
                    config[camelKey] = value.RemoveHtmlTags();
                }
            }
        }

        return config;
    }
}

Data Import/Export

public class DataExportService
{
    public string ExportEnumToJson<T>() where T : Enum
    {
        var enumData = EnumExtensions.GetDictionaryWithEnumNameAndDescription<T>();
        return JsonSerializer.Serialize(enumData, new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });
    }

    public string SanitizeForCsv(string input)
    {
        return input
            .RemoveHtmlTags()
            .Replace("\"", "\"\"")  // Escape quotes for CSV
            .Replace("\n", " ")     // Remove line breaks
            .Replace("\r", " ")
            .Trim();
    }

    public string CreateFilename(string baseName)
    {
        return baseName
            .RemoveHtmlTags()
            .ToKebabCase()
            .Truncate(50) +
            $"-{DateTime.UtcNow:yyyyMMdd-HHmmss}.csv";
    }
}

Performance Considerations

  • String Operations: Most string extensions use efficient algorithms and built-in .NET methods
  • Regex Caching: Validation methods use compiled and cached regex patterns
  • Type Operations: Reflection-based operations are optimized but should be used judiciously in hot paths
  • Memory Allocation: Extension methods minimize unnecessary string allocations where possible

Thread Safety

All extension methods in this package are thread-safe:

  • String extensions are stateless and operate on immutable strings
  • Enum extensions use reflection but don't modify state
  • Type extensions perform read-only operations on type metadata

Best Practices

String Extensions

  • Use validation extensions for user input sanitization
  • Prefer case conversion extensions over manual string manipulation
  • Use HTML removal methods when processing user-generated content

Enum Extensions

  • Always use [Description] attributes for user-facing enum values
  • Cache enum dictionaries in long-running applications
  • Use enum extensions for generating dropdowns and select lists

Type Extensions

  • Use type compatibility checking in generic constraint scenarios
  • Leverage interface finding for automatic service registration
  • Cache reflection results in performance-critical applications

Common Patterns

Input Validation Pipeline

public class InputValidator
{
    public Result<string> ValidateAndCleanInput(string input)
    {
        // Clean HTML
        var cleaned = input.RemoveHtmlTags().RemoveHtmlComments();

        // Validate not empty
        if (cleaned.IsNullOrWhiteSpace())
            return Error.Create("EMPTY_INPUT", "Input cannot be empty");

        // Validate length
        if (cleaned.Length > 1000)
            return Error.Create("INPUT_TOO_LONG", "Input exceeds maximum length");

        return Result.Success(cleaned.Trim());
    }
}

API Slug Generation

public class SlugGenerator
{
    public string GenerateSlug(string title)
    {
        return title
            .RemoveHtmlTags()
            .ToLowerInvariant()
            .ToKebabCase()
            .Truncate(50)
            .Trim('-');
    }
}
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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 was computed.  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 was computed.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
2.11.0 11 9/2/2025
2.10.0 99 8/22/2025
2.9.0 131 8/3/2025
2.8.2 229 5/15/2025
2.8.1 157 4/24/2025
2.8.0 133 4/22/2025
2.7.3 135 4/13/2025
2.7.2 166 4/6/2025
2.7.1 170 4/3/2025
2.7.0 165 4/3/2025
2.6.0 488 3/24/2025
2.5.1 126 3/14/2025
2.5.0 112 2/24/2025
2.4.1 139 10/2/2024
2.4.0 130 10/2/2024
2.3.0 130 10/1/2024
2.2.4 125 9/30/2024
2.2.3 121 9/28/2024
2.2.2 125 9/20/2024
2.2.1 131 9/17/2024
2.2.0 131 9/17/2024
2.1.0 144 8/12/2024
2.0.0 200 12/28/2023