NetEvolve.Arguments 3.2.0

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

NetEvolve.Arguments

NuGet Version NuGet Downloads License

A universal polyfill library that provides modern ArgumentNullException.ThrowIf* and ArgumentException.ThrowIf* helper methods across all .NET runtimes (.NET Standard 2.0+, .NET Framework 4.7.2+, .NET 6.0+), enabling consistent argument validation patterns regardless of target framework version.

Features

  • Universal Compatibility - Works seamlessly across .NET Framework 4.7.2+, .NET Standard 2.0+, and all modern .NET versions (6.0 through 10.0)
  • Modern API on Legacy Frameworks - Brings .NET 8+ argument validation APIs to older framework versions through polyfills
  • Zero Learning Curve - Uses the same API surface as modern .NET, making migration and cross-framework development effortless
  • Performance Optimized - Aggressive inlining, stack trace hiding, and minimal overhead for validation operations
  • Comprehensive Validation Suite - Over 40 validation methods covering nullability, ranges, collections, strings, dates, and more
  • CallerArgumentExpression Support - Automatic parameter name capture for clearer exception messages
  • Type-Safe Generic Methods - Strongly-typed validation with compile-time safety
  • Extended Validation Helpers - Additional validation methods beyond the standard .NET API for common scenarios

Installation

NuGet Package Manager

Install-Package NetEvolve.Arguments

.NET CLI

dotnet add package NetEvolve.Arguments

PackageReference

<PackageReference Include="NetEvolve.Arguments" />

Quick Start

using NetEvolve.Arguments;

public class UserService
{
    public void CreateUser(string username, string email, int age)
    {
        // Validate arguments with modern .NET 8+ API - works on all frameworks!
        ArgumentException.ThrowIfNullOrWhiteSpace(username);
        ArgumentException.ThrowIfNullOrWhiteSpace(email);
        ArgumentOutOfRangeException.ThrowIfNegative(age);
        ArgumentOutOfRangeException.ThrowIfGreaterThan(age, 150);

        // Your logic here
    }
}

Understanding the Polyfill Concept

NetEvolve.Arguments brings modern .NET 8+ argument validation APIs to older framework versions. This means:

  • On .NET 8+: The library delegates to the built-in framework methods (zero overhead)
  • On .NET 6-7: Provides polyfill implementations that match the .NET 8+ API exactly
  • On .NET Framework 4.7.2-4.8.1 and .NET Standard 2.0: Full polyfill implementation

This allows you to write code once using modern patterns and have it work consistently across all supported frameworks.

Usage

Null Validation

ThrowIfNull

Validates that a reference or pointer is not null.

public void ProcessData(object data)
{
    ArgumentNullException.ThrowIfNull(data);
    // data is guaranteed non-null here
}

// With unsafe pointers (requires unsafe context)
public unsafe void ProcessPointer(void* ptr)
{
    ArgumentNullException.ThrowIfNull(ptr);
    // ptr is guaranteed non-null here
}

String Validation

ThrowIfNullOrEmpty

Validates that a string is neither null nor empty.

public void SetUsername(string username)
{
    ArgumentException.ThrowIfNullOrEmpty(username);
    // username is guaranteed to have at least one character
}
ThrowIfNullOrWhiteSpace

Validates that a string is not null, empty, or whitespace-only.

public void SetDescription(string description)
{
    ArgumentException.ThrowIfNullOrWhiteSpace(description);
    // description is guaranteed to have non-whitespace content
}
ThrowIfLengthGreaterThan

Validates that a string does not exceed a maximum length.

public void SetTitle(string title)
{
    ArgumentException.ThrowIfLengthGreaterThan(title, 100);
    // title is guaranteed to be 100 characters or less
}
ThrowIfLengthLessThan

Validates that a string meets a minimum length requirement.

public void SetPassword(string password)
{
    ArgumentException.ThrowIfLengthLessThan(password, 8);
    // password is guaranteed to be at least 8 characters
}
ThrowIfLengthOutOfRange

Validates that a string length falls within a specified range.

public void SetPostalCode(string postalCode)
{
    ArgumentException.ThrowIfLengthOutOfRange(postalCode, 5, 10);
    // postalCode length is between 5 and 10 characters
}
ThrowIfContainsWhiteSpace

Validates that a string does not contain any whitespace characters.

public void SetIdentifier(string identifier)
{
    ArgumentException.ThrowIfContainsWhiteSpace(identifier);
    // identifier is guaranteed to have no spaces, tabs, or other whitespace
}

Collection Validation

ThrowIfNullOrEmpty (Collections)

Validates that a collection is neither null nor empty. Supports multiple collection types.

// IEnumerable<T>
public void ProcessItems(IEnumerable<string> items)
{
    ArgumentException.ThrowIfNullOrEmpty(items);
    // items is guaranteed to have at least one element
}

// ICollection<T>
public void ProcessList(ICollection<int> numbers)
{
    ArgumentException.ThrowIfNullOrEmpty(numbers);
}

// IReadOnlyCollection<T>
public void ProcessReadOnly(IReadOnlyCollection<string> values)
{
    ArgumentException.ThrowIfNullOrEmpty(values);
}

// Arrays
public void ProcessArray(string[] items)
{
    ArgumentException.ThrowIfNullOrEmpty(items);
}
ThrowIfCountGreaterThan

Validates that a collection does not exceed a maximum count.

public void ProcessBatch(ICollection<Order> orders)
{
    ArgumentException.ThrowIfCountGreaterThan(orders, 1000);
    // orders collection has at most 1000 items
}
ThrowIfCountLessThan

Validates that a collection meets a minimum count requirement.

public void ProcessTeam(IEnumerable<User> users)
{
    ArgumentException.ThrowIfCountLessThan(users, 2);
    // users collection has at least 2 members
}
ThrowIfCountOutOfRange

Validates that a collection count falls within a specified range.

public void ProcessGroup(IReadOnlyCollection<Person> people)
{
    ArgumentException.ThrowIfCountOutOfRange(people, 3, 10);
    // people collection has between 3 and 10 members
}
ThrowIfContainsDuplicates

Validates that a collection does not contain duplicate elements.

public void ProcessUniqueIds(IEnumerable<int> ids)
{
    ArgumentException.ThrowIfContainsDuplicates(ids);
    // ids collection contains only unique values
}

// With custom comparer
public void ProcessUniqueNames(IEnumerable<string> names)
{
    ArgumentException.ThrowIfContainsDuplicates(names, StringComparer.OrdinalIgnoreCase);
    // names collection contains unique values (case-insensitive)
}

Numeric Range Validation

ThrowIfZero

Validates that a numeric value is not zero.

public void SetDivisor(int divisor)
{
    ArgumentOutOfRangeException.ThrowIfZero(divisor);
    // divisor is guaranteed to be non-zero
}
ThrowIfNegative

Validates that a numeric value is not negative.

public void SetQuantity(int quantity)
{
    ArgumentOutOfRangeException.ThrowIfNegative(quantity);
    // quantity is guaranteed to be >= 0
}

// Works with nint on older frameworks
public void SetNativeInt(nint value)
{
    ArgumentOutOfRangeException.ThrowIfNegative(value);
}
ThrowIfNegativeOrZero

Validates that a numeric value is positive (greater than zero).

public void SetPrice(decimal price)
{
    ArgumentOutOfRangeException.ThrowIfNegativeOrZero(price);
    // price is guaranteed to be > 0
}
ThrowIfEqual

Validates that a value is not equal to a specified value.

public void SetStatus(int status)
{
    ArgumentOutOfRangeException.ThrowIfEqual(status, 0);
    // status is guaranteed to be non-zero
}
ThrowIfNotEqual

Validates that a value equals a specified value.

public void ProcessExpectedValue(int actual, int expected)
{
    ArgumentOutOfRangeException.ThrowIfNotEqual(actual, expected);
    // actual is guaranteed to equal expected
}
ThrowIfGreaterThan

Validates that a value does not exceed a maximum.

public void SetPercentage(int percentage)
{
    ArgumentOutOfRangeException.ThrowIfGreaterThan(percentage, 100);
    // percentage is guaranteed to be <= 100
}
ThrowIfGreaterThanOrEqual

Validates that a value is strictly less than a maximum.

public void SetIndex(int index, int arrayLength)
{
    ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, arrayLength);
    // index is guaranteed to be < arrayLength (valid array index)
}
ThrowIfLessThan

Validates that a value meets a minimum requirement.

public void SetAge(int age)
{
    ArgumentOutOfRangeException.ThrowIfLessThan(age, 18);
    // age is guaranteed to be >= 18
}
ThrowIfLessThanOrEqual

Validates that a value is strictly greater than a minimum.

public void SetRating(int rating)
{
    ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(rating, 0);
    // rating is guaranteed to be > 0
}
ThrowIfOutOfRange

Validates that a value falls within a specified range (inclusive).

public void SetVolume(int volume)
{
    ArgumentOutOfRangeException.ThrowIfOutOfRange(volume, 0, 100);
    // volume is guaranteed to be between 0 and 100 (inclusive)
}

Date and Time Validation

These methods are available on .NET 8.0+ only, providing validation for temporal values.

ThrowIfInPast (DateTimeOffset)

Validates that a DateTimeOffset is not in the past.

public void ScheduleEvent(DateTimeOffset eventTime)
{
    ArgumentOutOfRangeException.ThrowIfInPast(eventTime);
    // eventTime is guaranteed to be >= current UTC time
}

// With custom TimeProvider for testing
public void ScheduleEvent(DateTimeOffset eventTime, TimeProvider timeProvider)
{
    ArgumentOutOfRangeException.ThrowIfInPast(eventTime, timeProvider);
}
ThrowIfInFuture (DateTimeOffset)

Validates that a DateTimeOffset is not in the future.

public void RecordTransaction(DateTimeOffset timestamp)
{
    ArgumentOutOfRangeException.ThrowIfInFuture(timestamp);
    // timestamp is guaranteed to be <= current UTC time
}
ThrowIfInPast (DateTime)

Validates that a DateTime is not in the past.

public void ScheduleAppointment(DateTime appointmentTime)
{
    ArgumentOutOfRangeException.ThrowIfInPast(appointmentTime);
    // appointmentTime is guaranteed to be >= current UTC time
}
ThrowIfInFuture (DateTime)

Validates that a DateTime is not in the future.

public void LogActivity(DateTime activityTime)
{
    ArgumentOutOfRangeException.ThrowIfInFuture(activityTime);
    // activityTime is guaranteed to be <= current UTC time
}
ThrowIfInPast (DateOnly)

Validates that a DateOnly is not in the past.

public void BookEvent(DateOnly eventDate)
{
    ArgumentOutOfRangeException.ThrowIfInPast(eventDate);
    // eventDate is guaranteed to be >= today's date
}
ThrowIfInFuture (DateOnly)

Validates that a DateOnly is not in the future.

public void RecordBirthdate(DateOnly birthdate)
{
    ArgumentOutOfRangeException.ThrowIfInFuture(birthdate);
    // birthdate is guaranteed to be <= today's date
}

Special Type Validation

ThrowIfDefault

Validates that a value type is not its default value.

public void ProcessId(Guid id)
{
    ArgumentException.ThrowIfDefault(id);
    // id is guaranteed to not be default(Guid)
}
ThrowIfEmptyGuid

Validates that a GUID is not Guid.Empty.

public void SetUserId(Guid userId)
{
    ArgumentException.ThrowIfEmptyGuid(userId);
    // userId is guaranteed to not be Guid.Empty
}

Backward Compatible Argument Class (Obsolete)

For projects migrating from older codebases, the Argument class provides backward-compatible helper methods. These are marked as obsolete and delegate to the modern exception polyfills.

using NetEvolve.Arguments;

public void OldCodePattern(string value, int count)
{
    // Obsolete but functional - redirects to ArgumentException.ThrowIfNullOrEmpty
    Argument.ThrowIfNullOrEmpty(value);

    // Obsolete but functional - redirects to ArgumentOutOfRangeException.ThrowIfNegative
    Argument.ThrowIfNegative(count);
}

Migration Recommendation: Use the modern ArgumentNullException, ArgumentException, and ArgumentOutOfRangeException polyfill methods directly instead of the Argument class helpers.

Cross-Framework Examples

Example 1: .NET Framework 4.8 Project

// File: UserValidator.cs
// Target Framework: net48

using System;

public class UserValidator
{
    public void ValidateUser(string email, int age, string[] roles)
    {
        // Modern .NET 8+ API works perfectly on .NET Framework 4.8!
        ArgumentException.ThrowIfNullOrWhiteSpace(email);
        ArgumentOutOfRangeException.ThrowIfLessThan(age, 0);
        ArgumentOutOfRangeException.ThrowIfGreaterThan(age, 150);
        ArgumentException.ThrowIfNullOrEmpty(roles);
    }
}

Example 2: Multi-Targeting Library

// File: SharedLibrary.csproj
// <TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>

using System;
using System.Collections.Generic;

namespace SharedLibrary
{
    public class DataProcessor
    {
        // Same code works across all target frameworks
        public void Process(IEnumerable<string> items, int batchSize)
        {
            ArgumentException.ThrowIfNullOrEmpty(items);
            ArgumentOutOfRangeException.ThrowIfNegativeOrZero(batchSize);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(batchSize, 1000);

            // Process items...
        }
    }
}

Example 3: Modern .NET 10 with DateTimeOffset Validation

// File: EventScheduler.cs
// Target Framework: net10.0

using System;

public class EventScheduler
{
    private readonly TimeProvider _timeProvider;

    public EventScheduler(TimeProvider? timeProvider = null)
    {
        _timeProvider = timeProvider ?? TimeProvider.System;
    }

    public void ScheduleEvent(string title, DateTimeOffset startTime, DateTimeOffset endTime)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(title);
        ArgumentException.ThrowIfLengthGreaterThan(title, 200);

        // Date/time validation (available on .NET 8+)
        ArgumentOutOfRangeException.ThrowIfInPast(startTime, _timeProvider);
        ArgumentOutOfRangeException.ThrowIfInPast(endTime, _timeProvider);

        // Ensure end is after start
        if (endTime <= startTime)
        {
            throw new ArgumentException("End time must be after start time.", nameof(endTime));
        }
    }
}

Performance Considerations

NetEvolve.Arguments is designed with performance in mind:

  • Aggressive Inlining: Frequently-used validation methods use [MethodImpl(MethodImplOptions.AggressiveInlining)] for minimal call overhead
  • Stack Trace Optimization: Methods are marked with [StackTraceHidden] to produce cleaner exception stack traces
  • Zero Allocation on Success: Validation methods only allocate when throwing exceptions
  • Framework Delegation: On .NET 8+, methods delegate directly to framework implementations for optimal performance
  • Smart Collection Checks: Uses TryGetNonEnumeratedCount to avoid enumerating collections when possible

Benchmark Example

// On .NET 8+, this has virtually zero overhead
ArgumentException.ThrowIfNullOrWhiteSpace(username);

// Equivalent to calling the built-in .NET 8 method directly
// No additional layers, no wrapper overhead

Requirements

Supported Frameworks

  • .NET 10.0
  • .NET 9.0
  • .NET 8.0
  • .NET 7.0
  • .NET 6.0
  • .NET Standard 2.0 (enables support for .NET Framework 4.7.2+, Xamarin, Unity, and more)
  • .NET Framework 4.7.2 (Windows only)
  • .NET Framework 4.8 (Windows only)
  • .NET Framework 4.8.1 (Windows only)

Feature Availability by Framework

Feature Category .NET Framework 4.7.2-4.8.1 .NET Standard 2.0 .NET 6.0-7.0 .NET 8.0+
Null Validation ✅ (Framework Native)
String Validation ✅ (Framework Native)
Collection Validation
Numeric Range Validation ✅ (Framework Native)
DateTime/DateTimeOffset Validation
DateOnly Validation
Extended Collection Helpers
Special Type Validation

Edge Cases and Special Scenarios

Working with Nullable Value Types

public void ProcessNullableInt(int? value)
{
    // ThrowIfNull works with nullable value types
    ArgumentNullException.ThrowIfNull(value);

    // After validation, value is guaranteed non-null
    int actualValue = value.Value; // Safe - no NullReferenceException
}

Generic Type Constraints

public class Repository<T> where T : IComparable<T>
{
    public void SetMinValue(T minValue, T maxValue)
    {
        // Generic constraints ensure compile-time safety
        ArgumentOutOfRangeException.ThrowIfGreaterThan(minValue, maxValue);
    }
}

Collection Performance Notes

public void OptimizedCollectionCheck(IEnumerable<string> items)
{
    // Uses TryGetNonEnumeratedCount when possible
    // Avoids full enumeration for ICollection<T>, arrays, etc.
    ArgumentException.ThrowIfNullOrEmpty(items);

    // Only enumerates if count cannot be determined without enumeration
}

Thread Safety

All validation methods are stateless and thread-safe. They can be safely called from multiple threads concurrently.

public void ThreadSafeValidation(string input)
{
    // Safe to call from multiple threads
    ArgumentException.ThrowIfNullOrWhiteSpace(input);
}

Documentation

For complete solution documentation, architecture decisions, and contributing guidelines, visit the Arguments Repository.

Contributing

Contributions are welcome! Please read the Contributing Guidelines before submitting a pull request.

Support

License

This project is licensed under the MIT License - see the LICENSE file for details.


Made with ❤️ by the NetEvolve Team Visit us at https://www.daily-devops.net for more information about our services and solutions.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  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 is compatible.  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 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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 is compatible.  net48 is compatible.  net481 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  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.
  • .NETFramework 4.7.2

    • No dependencies.
  • .NETFramework 4.8

    • No dependencies.
  • .NETFramework 4.8.1

    • No dependencies.
  • .NETStandard 2.0

    • No dependencies.
  • net10.0

    • No dependencies.
  • net6.0

    • No dependencies.
  • net7.0

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on NetEvolve.Arguments:

Package Downloads
NetEvolve.Extensions.Tasks

This library provides simple extension methods for `Task`, `Task<T>`, `ValueTask` and `ValueTask<T>`.

NetEvolve.Guard

Basic input validation via the `Ensure`-class throws an `ArgumentException`, `ArgumentNullException` or other Exception types, if the conditions are not met. The second parameter `parameterName` from `Ensure.That(T value, string? parameterName = default!)` is optional and is automatically populated by .NET, based on the `CallerArgumentExpressionAttribute` functionality.

NetEvolve.Extensions.Strings

Library with common `string` extension methods for easy reuse.

NetEvolve.Logging.XUnit

Extensions for `ILogger` implementations to log messages to xUnit test output.

NetEvolve.FluentValue

The fluent value validation library provides a set of fluent interfaces to validate values.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.2.0 0 1/27/2026
3.1.0 2,267 1/11/2026
3.0.0 9,158 12/31/2025
2.0.17 9,027 11/30/2025
2.0.0 7,046 11/20/2025
1.3.134 3,072 10/22/2025
1.3.84 10,877 5/5/2025
1.3.77 536 5/1/2025
1.3.68 12,877 4/8/2025
1.3.43 5,575 2/2/2025
1.3.37 1,373 1/29/2025
1.3.0 5,305 12/16/2024
1.2.168 3,972 11/28/2024
1.2.100 7,207 9/11/2024
1.2.90 1,282 8/26/2024
1.2.50 5,586 6/23/2024
1.2.46 440 6/18/2024
1.2.12 5,855 5/21/2024
1.2.11 214 5/21/2024
1.2.0 326 4/26/2024
1.1.9 1,730 4/8/2024
1.1.3 1,700 4/5/2024
1.1.0 312 4/4/2024
1.0.123 3,204 2/17/2024
1.0.88 4,165 1/3/2024
1.0.65 5,243 11/17/2023
1.0.58 1,057 11/15/2023
1.0.8 3,958 8/29/2023
1.0.6 396 8/29/2023
1.0.5 617 8/28/2023