ScopeSelection 1.2.1

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

Scope Selection

A simple, portable library to make selection of subsets easy and abstract.

The Problem

When accessing a semi-hierarchical collection of items, you often want an easy way to tell if an element is in a particular subset.

Consider the following data class to support execution of Cucumber style clauses:

public class Clause
{
	public string Feature { get; init; } = "";
	public string Scenario { get; init; } = "";
	public string Keyword { get; init; } = "";
	public IReadOnlyList<string> Tags { get; init; } = [];

	public string Payload { get; set; } = "";
}

Compare that with different ways it may be bound:

public class StepBinding
{
	public string Feature { get; init; } = "";
	public string Scenario { get; init; } = "";
	public string Keyword { get; init; } = "";
	public IReadOnlyList<string> Tags { get; init; } = [];

	public required IBinding { get; set; }
}

public class StepArgumentTransformationBinding
{
	public string Feature { get; init; } = "";
	public string Scenario { get; init; } = "";
	public string Keyword { get; init; } = "";
	public IReadOnlyList<string> Tags { get; init; } = [];

	public required ITransformation { get; set; }
}

Such structuring proliferates and promotes redundant query logic.

The Solution

This can be solved by introducing an abstraction that encapsulates redundant structure.

public class Clause
{
	public required Scope { get; init }

	public string Payload { get; set; } = "";
}

public class StepBinding
{
	public required Scope { get; init }

	public required IBinding { get; set; }
}

public class StepArgumentTransformationBinding
{
	public required Scope { get; init }

	public required ITransformation { get; set; }
}

Encapsulating redundant structure provides an opportunity to encapsulate redundant logic, too. Instead of sophisticated logic being repeated, you can hide them behind a single method you use in a where LINQ operation.

var Bindings = AllBindings.Where(B => Operation.Scope.IsSatisfiedBy(B.Scope));

At its core, this package provides the abstraction to solve this problem, but it goes a little further.

Built-In Scope Types

While the fundamental purpose of the library is to provide the contract, this package also provides two built-in types of scope:

  1. A scope that operates by supply and demand of tokens
  2. A scope that combines two other scopes into a multidimensional scope

Later, an hierarchical built-in may be added.

Supply and Demand

A supply and demand scope space involves explicit declarations involving tokens. These tokens can be of any type.

Following is an example of use.

  [TestMethod]
  public void SelectItem()
  {
    var ScopeSpace = ScopeSpaces.SupplyAndDemand<ClauseType>();
    var BindingScope = ScopeSpace.Supply(Given);

    var Included = ScopeSpace.Demand(Given).IsSatisfiedBy(BindingScope);

    Included.ShouldBeTrue();
  }

  [TestMethod]
  public void FailToSelectItem()
  {
    var ScopeSpace = ScopeSpaces.SupplyAndDemand<ClauseType>();
    var BindingScope = ScopeSpace.Supply([Given, Then]);

    var Included = ScopeSpace.Demand(When).IsSatisfiedBy(BindingScope);

    Included.ShouldBeFalse();
  }

Composite

A composite scope space is multi-dimensional.

  [TestMethod]
  public void SelectItemInCompositeSpace()
  {
    var ClauseTypes = ScopeSpaces.SupplyAndDemand<ClauseType>();
    var Features = ScopeSpaces.SupplyAndDemand<string>();
    var CompositeSpace = ScopeSpaces.Composite(ClauseTypes, Features);
    var BindingScope = CompositeSpace.Combine(ClauseTypes.Any, Features.Supply("Scope Resolution"));

    var Included = CompositeSpace.Combine(ClauseTypes.Demand(Given), Features.Any).IsSatisfiedBy(BindingScope);

    Included.ShouldBeTrue();
  }

  [TestMethod]
  public void FailCompositeSelectionDueToOneDimension()
  {
    var ClauseTypes = ScopeSpaces.SupplyAndDemand<ClauseType>();
    var Features = ScopeSpaces.SupplyAndDemand<string>();
    var CompositeSpace = ScopeSpaces.Composite(ClauseTypes, Features);
    var BindingScope = CompositeSpace.Combine(ClauseTypes.Unspecified, Features.Supply("Scope Resolution"));

    var Included = CompositeSpace.Combine(ClauseTypes.Demand(Given), Features.Any).IsSatisfiedBy(BindingScope);

    Included.ShouldBeFalse();
  }

It does not matter the two underlying dimensions are. You can even have two dimensions from the exact same type of space.

Distinct Scope Spaces

Both the composite and the supply and demand scope spaces are distinct. That means that all scopes must come from the same origin space to be unioned, intersected, and compared.

Scopes from different spaces that have relational operations run on them will generate InvalidOperationExceptions. This mirrors at runtime the behavior you alreay get from the compiler when dealing with scopes of different type.

The Null Scope Space

There is one more built-in type of scope: the null scope space. This models having no scope partitioning at all.

Every scope in this space is always satisfied by every other object in the same space and the spaces are not considered distinct.

Contributing

Feel free to reach out to me on GitHub or via LinkedIn.

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 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 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.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on ScopeSelection:

Package Downloads
LineParser

A parser for small blocks of text that supports recursive, extensible patterns.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.1 133 1/9/2026
1.2.0 81 1/9/2026
1.1.0 93 1/9/2026