Between 1.0.1

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

Between - Comparison Extensions for C#

NuGet License: MIT

A lightweight and generic library for C# that provides elegant extension methods to check if a value is between two bounds.

Syntactic sugar for range comparisons that makes your code more readable and expressive, inspired by SQL's BETWEEN operator.

?? Features

  • Syntactic Sugar: Clean, readable syntax that replaces verbose comparison code
  • Generic: Works with any type that implements IComparable<T>
  • Flexible: Supports inclusive and exclusive comparisons with granular control
  • Performance: No overhead, direct compilation - just syntactic sugar!
  • Multi-framework: Supports .NET Framework 4.6, .NET Standard 2.0, .NET 5, 6, 7, and 8
  • Type-safe: Fully typed with compile-time validation
  • Well documented: Complete IntelliSense with XML documentation

?? Installation

Install the NuGet package using the .NET CLI:

dotnet add package Between

Or using the Package Manager Console:

Install-Package Between

?? Usage

Why Use This Library? (Syntactic Sugar Explained)

Instead of writing verbose comparison code:

// ? Traditional way - verbose and harder to read
if (age >= 18 && age <= 35)
{
    // ...
}

// ? With Between - clean and expressive syntactic sugar
if (age.Between(18, 35))
{
    // ...
}

This library is syntactic sugar - it doesn't add functionality, but makes your code more readable and maintainable by expressing intent clearly.

More Comparison Examples
Traditional C# With Between (Syntactic Sugar)
if (value >= 10 && value <= 20) if (value.Between(10, 20))
if (value > 10 && value < 20) if (value.Between(10, 20, BetweenBounds.Exclusive))
if (value > 10 && value <= 20) if (value.Between(10, 20, BetweenBounds.ExcludeLower))
if (value >= 10 && value < 20) if (value.Between(10, 20, BetweenBounds.ExcludeUpper))
numbers.Where(n => n >= 10 && n <= 20) numbers.Where(n => n.Between(10, 20))

Basic Usage

using Between;

// Integers
int age = 25;
bool isYoungAdult = age.Between(18, 35); // true

// Decimals
double temperature = 23.5;
bool isComfortable = temperature.Between(20.0, 26.0); // true

// Dates
DateTime date = new DateTime(2023, 6, 15);
DateTime start = new DateTime(2023, 1, 1);
DateTime end = new DateTime(2023, 12, 31);
bool thisYear = date.Between(start, end); // true

// Strings (alphabetical comparison)
string name = "Carlos";
bool betweenAandD = name.Between("Alberto", "Daniel"); // true

// Decimals
decimal price = 99.99m;
bool inRange = price.Between(50.0m, 150.0m); // true

Boundary Control with BetweenBounds Enum

The library provides granular control over boundary inclusion through the BetweenBounds enum:

int value = 10;

// Inclusive (default) - includes both bounds [10, 20]
value.Between(10, 20, BetweenBounds.Inclusive); // true (10 >= 10 && 10 <= 20)

// Exclusive - excludes both bounds (10, 20)
value.Between(10, 20, BetweenBounds.Exclusive); // false (10 > 10 && 10 < 20)

// ExcludeLower - excludes only lower bound (10, 20]
value.Between(10, 20, BetweenBounds.ExcludeLower); // false (10 > 10 && 10 <= 20)

// ExcludeUpper - excludes only upper bound [10, 20)
value.Between(10, 20, BetweenBounds.ExcludeUpper); // true (10 >= 10 && 10 < 20)

Examples with Different Boundary Modes

int value = 15;

// All will return true for value = 15
value.Between(10, 20, BetweenBounds.Inclusive);     // true
value.Between(10, 20, BetweenBounds.Exclusive);     // true
value.Between(10, 20, BetweenBounds.ExcludeLower);  // true
value.Between(10, 20, BetweenBounds.ExcludeUpper);  // true

// Edge cases with value = 10
value = 10;
value.Between(10, 20, BetweenBounds.Inclusive);     // true  (includes lower)
value.Between(10, 20, BetweenBounds.Exclusive);     // false (excludes lower)
value.Between(10, 20, BetweenBounds.ExcludeLower);  // false (excludes lower)
value.Between(10, 20, BetweenBounds.ExcludeUpper);  // true  (includes lower)

// Edge cases with value = 20
value = 20;
value.Between(10, 20, BetweenBounds.Inclusive);     // true  (includes upper)
value.Between(10, 20, BetweenBounds.Exclusive);     // false (excludes upper)
value.Between(10, 20, BetweenBounds.ExcludeLower);  // true  (includes upper)
value.Between(10, 20, BetweenBounds.ExcludeUpper);  // false (excludes upper)

Backwards Compatibility

The library maintains backwards compatibility with the boolean parameter:

int value = 10;
value.Between(10, 20); // true (inclusive by default)
value.Between(10, 20, inclusive: false); // false (exclusive)
value.Between(10, 20, inclusive: true); // true (inclusive)

Custom Types

Works with any type that implements IComparable<T>:

public class Person : IComparable<Person>
{
    public string Name { get; set; }
    public int Age { get; set; }

    public int CompareTo(Person other)
    {
        return Age.CompareTo(other.Age);
    }
}

var person = new Person { Name = "Ana", Age = 30 };
var min = new Person { Name = "Min", Age = 18 };
var max = new Person { Name = "Max", Age = 65 };

bool inWorkingAgeRange = person.Between(min, max); // true

?? Use Cases

Age Validation

public bool IsAdult(int age)
{
    return age.Between(18, 120);
}

public bool IsChild(int age)
{
    return age.Between(0, 12, BetweenBounds.ExcludeUpper);
}

public bool IsTeenager(int age)
{
    return age.Between(13, 19, BetweenBounds.Inclusive);
}

Date Validation

public bool IsBusinessHours(DateTime time)
{
    var start = new DateTime(time.Year, time.Month, time.Day, 9, 0, 0);
    var end = new DateTime(time.Year, time.Month, time.Day, 18, 0, 0);
    return time.Between(start, end);
}

public bool IsInCurrentYear(DateTime date)
{
    var yearStart = new DateTime(DateTime.Now.Year, 1, 1);
    var yearEnd = new DateTime(DateTime.Now.Year, 12, 31);
    return date.Between(yearStart, yearEnd);
}

Numeric Range Validation

public bool IsSafeTemperature(double temperature)
{
    return temperature.Between(-10.0, 40.0);
}

public bool IsValidPrice(decimal price)
{
    return price.Between(0.01m, 999999.99m, BetweenBounds.Inclusive);
}

Collection Filtering

The syntactic sugar shines in LINQ queries:

// ? Without Between - harder to read
var inRange = numbers.Where(n => n >= 10 && n <= 20).ToList();

// ? With Between - clear and concise
var numbers = new List<int> { 1, 5, 10, 15, 20, 25, 30 };
var inRange = numbers.Where(n => n.Between(10, 20)).ToList();
// Result: [10, 15, 20]

// Complex example with multiple conditions
var affordablePrices = products
    .Where(p => p.Price.Between(50.0m, 100.0m))
    .ToList();

?? API Reference

BetweenBounds Enum

public enum BetweenBounds
{
    Inclusive = 0,      // Both bounds included [min, max]
    Exclusive = 1,      // Both bounds excluded (min, max)
    ExcludeLower = 2,   // Lower bound excluded (min, max]
    ExcludeUpper = 3    // Upper bound excluded [min, max)
}

Between Method (with enum)

public static bool Between<T>(this T value, T min, T max, BetweenBounds bounds = BetweenBounds.Inclusive) 
    where T : IComparable<T>
Parameters
  • value: The value to evaluate
  • min: The lower bound of the range
  • max: The upper bound of the range
  • bounds (optional):
    • BetweenBounds.Inclusive (default): Includes both bounds (>=, ⇐)
    • BetweenBounds.Exclusive: Excludes both bounds (>, <)
    • BetweenBounds.ExcludeLower: Excludes only lower bound (>, ⇐)
    • BetweenBounds.ExcludeUpper: Excludes only upper bound (>=, <)
Returns

bool: true if the value is within the specified range; otherwise, false.

Exceptions
  • ArgumentNullException: Thrown if value, min, or max are null (for reference types).

Between Method (backwards compatibility)

public static bool Between<T>(this T value, T min, T max, bool inclusive = true) 
    where T : IComparable<T>
Parameters
  • value: The value to evaluate
  • min: The lower bound of the range
  • max: The upper bound of the range
  • inclusive (optional):
    • true (default): Includes both bounds (>=, ⇐)
    • false: Excludes both bounds (>, <)

?? Tests

The library includes a comprehensive unit test suite with xUnit covering:

  • ? Numeric types (int, double, decimal)
  • ? Dates (DateTime)
  • ? Strings
  • ? Custom types with IComparable<T>
  • ? All boundary modes (Inclusive, Exclusive, ExcludeLower, ExcludeUpper)
  • ? Edge cases (boundary values)
  • ? Null value validation

To run the tests:

cd Between.Tests
dotnet test

?? Performance

The Between method has excellent performance because:

  • No unnecessary boxing/unboxing
  • Uses the native CompareTo method of the type
  • Compiles inline in most cases
  • No additional memory allocations

?? Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a branch for your feature (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

?? License

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

?? Acknowledgments

Inspired by SQL's BETWEEN operator, this library brings the same intuitive syntax to C# as syntactic sugar.

Just like SQL:

SELECT * FROM Users WHERE age BETWEEN 18 AND 65

Now in C#:

users.Where(u => u.Age.Between(18, 65))

The goal is to make C# code more expressive and readable through elegant syntactic sugar.

?? Support

If you find a bug or have a suggestion, please open an issue.


Like the project? Give it a ? on GitHub!

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  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 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 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 net46 is compatible.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
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.6

    • No dependencies.
  • .NETStandard 2.0

    • No dependencies.
  • net5.0

    • No dependencies.
  • net6.0

    • No dependencies.
  • net7.0

    • No dependencies.
  • net8.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
1.0.1 51 2/3/2026