FractalDataWorks.Collections 0.6.0-rc.1

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

FractalDataWorks.Collections

Source-generated type collections for cross-project extensible type discovery in the FractalDataWorks ecosystem. Provides compile-time type safety using FrozenDictionary (on .NET 8+) or ImmutableDictionary (on netstandard2.0) for type collections where downstream developers can add their own options.

Overview

The Collections system provides cross-project type discovery for extensible type systems where:

  • Collections are placed in abstractions projects for discoverability
  • Base Types are in concrete projects and MUST inherit from TypeOptionBase<TKey, T> where TKey : IEquatable<TKey>
  • Interfaces define the contract and MUST extend ITypeOption<TKey, T>
  • Type Options can be added by downstream developers in any project
  • TypeCollections themselves ARE TypeOptions with int Ids (hash of collection name), enabling parent-child nesting via TypeOption

Key Architecture Insight: Two Key Types

TypeCollections have TWO separate key types:

  1. Collection's Own Id (always int) - Used when the collection itself is treated as a TypeOption

    • Enables parent-child collections via TypeOption
    • Auto-generated from collection type name hash
  2. TypeOptions' Keys (TKey) - Used for looking up TypeOptions within the collection

    • Extracted from base type's ITypeOption<TKey, T> implementation
    • Can be int, string, Guid, or any IEquatable<TKey> type
    • Example: CommandTypeBase : ITypeOption<int, CommandTypeBase> → TKey = int

Required Architecture Components

CRITICAL: All TypeCollections MUST follow this 4-component pattern. Missing any component will cause compilation failures or runtime issues.

1. Interface (in Abstractions Project)

REQUIRED: Must extend ITypeOption<TKey, TBase>

From IConnectionState.cs:1-10:

using FractalDataWorks.Collections;

namespace FractalDataWorks.Services.Connections.Abstractions;

/// <summary>
/// Interface for connection states.
/// </summary>
public interface IConnectionState : ITypeOption<int, ConnectionStateBase>
{
}

Why ITypeOption<TKey, TBase> Format:

  • TKey (first parameter) = int - The key type for dictionary lookups
  • TBase (second parameter) = ConnectionStateBase - The base type (CRTP pattern)

2. Base Class (in Concrete/Abstractions Project)

REQUIRED: Must inherit from TypeOptionBase<TKey, T> AND implement the interface

From ConnectionStateBase.cs:1-22:

using FractalDataWorks.Collections;

namespace FractalDataWorks.Services.Connections.Abstractions;

/// <summary>
/// Base class for connection states in the FractalDataWorks framework.
/// </summary>
/// <remarks>
/// Connection states help track the lifecycle of external connections and enable
/// proper connection management, pooling, and error handling throughout the framework.
/// </remarks>
public abstract class ConnectionStateBase : TypeOptionBase<int, ConnectionStateBase>, IConnectionState
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ConnectionStateBase"/> class.
    /// </summary>
    /// <param name="id">The unique identifier for this connection state.</param>
    /// <param name="name">The name of this connection state.</param>
    protected ConnectionStateBase(int id, string name) : base(id, name)
    {
    }
}

Why TypeOptionBase<TKey, T> is Required:

  • Provides TKey Id property (e.g., int Id) that source generator uses
  • Provides string Name and string Category properties
  • Ensures consistent behavior across all TypeCollections
  • Enables dictionary lookups: FrozenDictionary<TKey, TBase> (.NET 8+) or ImmutableDictionary<TKey, TBase> (netstandard2.0)
  • Supports [TypeLookup] attributes for alternate keys (e.g., [TypeLookup("ById")], [TypeLookup("ByName")])

Flexible Key Types:

  • int - Most common (IDs, enums)
  • string - Named lookups (command names, identifiers)
  • Guid - Unique identifiers
  • Any type implementing IEquatable<TKey>

3. TypeCollection (in Abstractions Project)

REQUIRED: Must be marked with [TypeCollection] and extend TypeCollectionBase<TBase, TInterface>

CRITICAL: NO TKey parameter on TypeCollectionBase - it's extracted from the base type!

From ConnectionStates.cs:1-16:

using FractalDataWorks.Collections;
using FractalDataWorks.Collections.Attributes;
using FractalDataWorks.Services.Connections.Abstractions;
using System.Diagnostics.CodeAnalysis;

namespace FractalDataWorks.Services.Connections.Abstractions;

/// <summary>
/// Collection of connection states.
/// </summary>
[ExcludeFromCodeCoverage]
[TypeCollection(typeof(ConnectionStateBase), typeof(IConnectionState), typeof(ConnectionStates))]
public abstract partial class ConnectionStates : TypeCollectionBase<ConnectionStateBase, IConnectionState>
{

}

How TKey is Discovered:

  1. Generator looks at ConnectionStateBase
  2. Finds ConnectionStateBase : TypeOptionBase<int, ConnectionStateBase>
  3. Extracts TKey = int from the ITypeOption<int, ...> implementation
  4. Generates: FrozenDictionary<int, ConnectionStateBase> _all

TypeCollection Inherits from TypeOptionBase:

  • TypeCollectionBase<TBase, TInterface> inherits from TypeOptionBase<int, TypeCollectionBase<TBase, TInterface>>
  • Collections have int Id (hash of collection name) and string Name
  • This enables collections to be nested via TypeOption (parent-child pattern)

TypeCollection Attribute Parameters:

  1. typeof(ConnectionStateBase) - The base class to discover (must inherit from TypeOptionBase<TKey, T>)
  2. typeof(IConnectionState) - The interface type to return (must extend ITypeOption<TKey, T>)
  3. typeof(ConnectionStates) - This collection class

4. Concrete TypeOptions (in Any Project)

REQUIRED: Must be marked with [TypeOption] and inherit from the base class

From OpenConnectionState.cs:1-11:

using FractalDataWorks.Collections.Attributes;
using System.Diagnostics.CodeAnalysis;

namespace FractalDataWorks.Services.Connections.Abstractions;

/// <summary>
/// The connection is open and ready for use.
/// </summary>
[ExcludeFromCodeCoverage]
[TypeOption(typeof(ConnectionStates), "Open")]
public sealed class OpenConnectionState() : ConnectionStateBase(3, "Open");

TypeOption Attribute Parameters:

  1. typeof(ConnectionStates) - The collection type this option belongs to
  2. "Open" - Display name (becomes property name: ConnectionStates.Open)

Complete Working Example: Connection States

This example shows the EXACT pattern that MUST be followed. All code is from actual source files in the FractalDataWorks codebase.

TypeOptions in the Connection States Collection

The following TypeOptions are defined in the FractalDataWorks.Services.Connections.Abstractions project:

From ClosedConnectionState.cs:1-11:

using FractalDataWorks.Collections.Attributes;
using System.Diagnostics.CodeAnalysis;

namespace FractalDataWorks.Services.Connections.Abstractions;

/// <summary>
/// The connection is closed.
/// </summary>
[ExcludeFromCodeCoverage]
[TypeOption(typeof(ConnectionStates), "Closed")]
public sealed class ClosedConnectionState() : ConnectionStateBase(6, "Closed");

From OpeningConnectionState.cs:1-11:

using FractalDataWorks.Collections.Attributes;
using System.Diagnostics.CodeAnalysis;

namespace FractalDataWorks.Services.Connections.Abstractions;

/// <summary>
/// The connection is currently being opened.
/// </summary>
[ExcludeFromCodeCoverage]
[TypeOption(typeof(ConnectionStates), "Opening")]
public sealed class OpeningConnectionState() : ConnectionStateBase(2, "Opening");

From ExecutingConnectionState.cs:1-11:

using FractalDataWorks.Collections.Attributes;
using System.Diagnostics.CodeAnalysis;

namespace FractalDataWorks.Services.Connections.Abstractions;

/// <summary>
/// The connection is currently executing an operation.
/// </summary>
[ExcludeFromCodeCoverage]
[TypeOption(typeof(ConnectionStates), "Executing")]
public sealed class ExecutingConnectionState() : ConnectionStateBase(4, "Executing");

Generated API Usage

The source generator creates lookup methods and static properties. From the generated code in ConnectionStates.TypeCollection.g.cs:

// Static properties - get concrete types directly
OpenConnectionState open = ConnectionStates.Open;
ClosedConnectionState closed = ConnectionStates.Closed;
ExecutingConnectionState executing = ConnectionStates.Executing;

// Lookup by Id - returns interface type, Empty if not found
IConnectionState byId = ConnectionStates.ById(3);        // Returns Open
IConnectionState notFound = ConnectionStates.ById(999);  // Returns Empty

// Lookup by Name - returns interface type, Empty if not found
IConnectionState byName = ConnectionStates.ByName("Executing");  // Returns Executing

// Collection access - returns all registered TypeOptions
IReadOnlyCollection<IConnectionState> all = ConnectionStates.All();

// Empty sentinel for failed lookups
IConnectionState empty = ConnectionStates.Empty;

Architecture Pattern Overview

Project Structure:
┌─────────────────────────────────────────────────────────────────────────┐
│ Abstractions Project                                                     │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 1. IConnectionState : ITypeOption<int, ConnectionStateBase>         │ │
│ │ 2. ConnectionStateBase : TypeOptionBase<int, ConnectionStateBase>,  │ │
│ │                          IConnectionState                           │ │
│ │ 3. [TypeCollection] ConnectionStates :                              │ │
│ │                     TypeCollectionBase<ConnectionStateBase,         │ │
│ │                                        IConnectionState>            │ │
│ │ 4. [TypeOption] OpenConnectionState : ConnectionStateBase           │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
            ▼ Source Generator Processes
┌─────────────────────────────────────────────────────────────────────────┐
│ Generated Code (partial class ConnectionStates)                         │
│ - Static properties: Open, Closed, Opening, etc.                        │
│ - Static methods: ById(int), ByName(string), All()                      │
│ - FrozenDictionary backing stores (.NET 8+)                             │
│ - ImmutableDictionary backing stores (netstandard2.0)                   │
└─────────────────────────────────────────────────────────────────────────┘

TypeOptionBase<TKey, T> - Why It's Required

TypeOptionBase<TKey, T> provides essential functionality that the source generator depends on.

From TypeOptionBase.cs:12-88:

public abstract class TypeOptionBase<TKey, T> : ITypeOption<TKey, T>
    where TKey : IEquatable<TKey>
    where T : ITypeOption<TKey, T>
{
    /// <summary>
    /// Gets the unique identifier for this type option value.
    /// </summary>
    [TypeLookup("ById")]
    public virtual TKey Id { get; }

    /// <summary>
    /// Gets the name of this type option value.
    /// </summary>
    [TypeLookup("ByName")]
    public string Name { get; }

    /// <summary>
    /// Gets the category of this type option value.
    /// </summary>
    public string Category => string.IsNullOrEmpty(_category) ? "NotCategorized" : _category;

    /// <summary>
    /// Gets the configuration key for this type option value.
    /// Used for configuration lookups and service registration.
    /// </summary>
    public string ConfigurationKey { get; }

    /// <summary>
    /// Gets the display name for this type option value.
    /// Used for user-facing displays and documentation.
    /// </summary>
    public string DisplayName { get; }

    /// <summary>
    /// Gets the description of this type option value.
    /// Provides detailed information about what this option does.
    /// </summary>
    public string Description { get; }

    protected TypeOptionBase(TKey id, string name) : this(id, name, string.Empty)
    {
    }

    protected TypeOptionBase(TKey id, string name, string? category)
    {
        if (name == null) throw new ArgumentNullException(nameof(name));

        Id = id;
        Name = name;
        _category = category ?? string.Empty;
        ConfigurationKey = $"TypeOptions:{name}";
        DisplayName = name;
        Description = $"Type option: {name}";
    }
}

What the Source Generator Does:

  1. Scans for [TypeOption] attributes
  2. Reads Id and Name from TypeOptionBase properties (via [TypeLookup] attributes)
  3. Generates FrozenDictionary<TKey, T> for ID lookups (.NET 8+) or ImmutableDictionary<TKey, T> (netstandard2.0)
  4. Generates FrozenDictionary<string, T> for name lookups
  5. Creates static properties using the TypeOption name

Without TypeOptionBase: Generator cannot read Id/Name at compile time, causing build failures.

Project Structure and Source Generator References

Abstractions Project (Where TypeCollection Lives)

<ItemGroup>
  
  <PackageReference Include="FractalDataWorks.Collections" Version="*" />

  
  <PackageReference Include="FractalDataWorks.Collections.SourceGenerators" Version="*">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
  </PackageReference>
</ItemGroup>

Concrete Project (Where TypeOptions Are Implemented)

<ItemGroup>
  
  <ProjectReference Include="..\Project.Abstractions\Project.Abstractions.csproj" />

  
  <ProjectReference Include="..\FractalDataWorks.Collections.SourceGenerators\FractalDataWorks.Collections.SourceGenerators.csproj"
                    OutputItemType="Analyzer"
                    ReferenceOutputAssembly="false"
                    PrivateAssets="none" />

  
  <None Include="..\FractalDataWorks.Collections.SourceGenerators\bin\$(Configuration)\netstandard2.0\FractalDataWorks.Collections.SourceGenerators.dll"
        Pack="true"
        PackagePath="analyzers/dotnet/cs"
        Visible="false"
        Condition="Exists('..\FractalDataWorks.Collections.SourceGenerators\bin\$(Configuration)\netstandard2.0\FractalDataWorks.Collections.SourceGenerators.dll')" />
</ItemGroup>

Critical Settings Explained:

  • OutputItemType="Analyzer" - Makes project reference act as analyzer
  • ReferenceOutputAssembly="false" - Don't reference DLL at compile time
  • PrivateAssets="none" - CRITICAL: Propagates generator to consuming projects
  • <None Include=...> - Embeds generator DLL so consumers can access generated code

Consumer Projects

<ItemGroup>
  
  <ProjectReference Include="..\Project\Project.csproj" />

  
  
</ItemGroup>

Common Architecture Mistakes

WRONG: Missing TypeOptionBase

// THIS WILL NOT WORK
public abstract class FilterOperatorBase  // Missing: TypeOptionBase inheritance
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Problem: Source generator cannot read Id/Name at compile time.

WRONG: Missing ITypeOption Interface

// THIS WILL NOT WORK
public interface IFilterOperator  // Missing: ITypeOption<TKey, TBase> extension
{
}

Problem: Type constraints fail, collection cannot be properly typed.

WRONG: Base Class Not Implementing Interface

// THIS WILL NOT WORK
public abstract class FilterOperatorBase : TypeOptionBase<int, FilterOperatorBase>
    // Missing: , IFilterOperator
{
}

Problem: Generic constraints broken, compilation fails.

WRONG: Wrong TypeCollection Parameters

// THIS WILL NOT WORK
[TypeCollection(typeof(FilterOperatorBase), typeof(FilterOperatorBase), typeof(FilterOperators))]
    // Wrong: Second parameter should be IFilterOperator interface
public abstract partial class FilterOperators : TypeCollectionBase<FilterOperatorBase, FilterOperatorBase>
{
}

Problem: Loses polymorphism benefits, breaks interface abstraction.

CORRECT: Complete 4-Component Pattern

See the Connection States example above for the correct pattern from actual source files. The pattern requires:

  1. Interface extends ITypeOption<TKey, TBase> (e.g., IConnectionState : ITypeOption<int, ConnectionStateBase>)
  2. Base class inherits TypeOptionBase<TKey, T> AND implements interface
  3. TypeCollection with correct parameters: (typeof(Base), typeof(Interface), typeof(Collection))
  4. TypeOptions marked with [TypeOption] and inherit from base class

Generated API

All collections automatically generate the following. From the generated ConnectionStates.TypeCollection.g.cs:

Static Properties (One Per TypeOption)

// Returns concrete type, not interface
public static ClosedConnectionState Closed { get; }
public static OpeningConnectionState Opening { get; }
public static OpenConnectionState Open { get; }
public static ExecutingConnectionState Executing { get; }
// ... one for each TypeOption

Lookup Methods (From TypeOptionBase Properties with [TypeLookup] attributes)

// Primary key lookup (uses Id property with [TypeLookup("ById")])
// Returns Empty if not found
public static IConnectionState ById(int value);

// Name lookup (uses Name property with [TypeLookup("ByName")])
// Returns Empty if not found
public static IConnectionState ByName(string value);

Collection Methods

// Returns all registered TypeOptions
public static IReadOnlyCollection<IConnectionState> All();

// Empty sentinel instance for failed lookups (property, not method)
public static IConnectionState Empty { get; }

Performance Characteristics

  • Dictionary Lookups: Uses FrozenDictionary for ID/name lookups on .NET 8+, ImmutableDictionary on netstandard2.0
  • Compile-time Discovery: All types validated and discovered at compile time
  • Thread Safety: All generated collections are immutable and thread-safe
  • Cross-Assembly Discovery: Finds TypeOptions across all referenced assemblies

Validation Rules

  1. TypeOptionBase Required: Base classes MUST inherit from TypeOptionBase<TKey, T>
  2. ITypeOption Required: Interfaces MUST extend ITypeOption<TKey, TBase>
  3. Interface Implementation: Base classes MUST implement the interface
  4. TypeOption Attribute Required: Concrete types MUST have [TypeOption(typeof(Collection), "Name")]
  5. Unique IDs: Each TypeOption must have a unique ID within its collection
  6. Unique Names: Each TypeOption must have a unique name within its collection
  7. Generic Consistency: TGeneric must match interface type in TypeCollection attribute

Error Codes

  • TC001: Type inherits from collection base but missing [TypeOption] attribute
  • TC002: TGeneric in base class doesn't match defaultReturnType in attribute
  • TC003: TBase in base class doesn't match baseType in attribute
  • TC004: Duplicate option names in collection
  • TC005: Collection not found for TypeOption attribute
  • TC006: Base class doesn't inherit from TypeOptionBase<TKey, T>
  • TC007: Interface doesn't extend ITypeOption<TKey, TBase>

Best Practices

  1. Follow the 4-Component Pattern: Interface + Base + Collection + TypeOptions
  2. Abstractions Placement: Place collections in abstractions for maximum discoverability
  3. TypeOptionBase Inheritance: Always inherit from TypeOptionBase<TKey, T>
  4. Descriptive Names: Use clear, meaningful names in [TypeOption] attributes
  5. Unique IDs: Assign unique IDs within the collection
  6. Primary Constructors: Use C# 12 primary constructors for concise TypeOption syntax
  7. Proper Generator References: Use PrivateAssets="none" and embed the generator DLL

Cross-Project Extensibility

Any project can add new TypeOptions by inheriting from the base class and marking with [TypeOption]. The source generator will discover TypeOptions across all referenced assemblies.

Example pattern (not actual source - for illustration):

// In MyCustom.Extensions project
using FractalDataWorks.Collections.Attributes;
using FractalDataWorks.Services.Connections.Abstractions;

[TypeOption(typeof(ConnectionStates), "CustomState")]
public sealed class CustomConnectionState() : ConnectionStateBase(100, "CustomState");

After building, the custom state is available via ConnectionStates.ByName("CustomState").

This enables plugin architectures where core defines contracts (collections + base types + interfaces) and implementations can be provided by any assembly.

Deferred Freeze Pattern (Cross-Assembly Registration)

TypeCollections use a deferred freeze pattern to support cross-assembly registration via NuGet packages. This ensures TypeOptions defined in separate packages are registered before the collection is accessed.

The Problem

sequenceDiagram
    participant App as Application
    participant Col as ConnectionStates
    participant Lib as Extensions Package

    Note over App: Application starts
    App->>Col: ConnectionStates.All()
    Note over Col: Collection freezes!
    Col-->>App: Returns built-in states only
    Note over Lib: Custom states never registered

Static constructors only run when something in that assembly is accessed. If you call ConnectionStates.All() before loading custom extensions, those options aren't included.

The Solution

Collections stay mutable until first access, then freeze into a FrozenDictionary:

flowchart TB
    subgraph BeforeAccess["Before First Access"]
        A[Module initializers run] --> B[RegisterMember adds to pending list]
        B --> C[Static constructors run]
        C --> D[More RegisterMember calls]
    end

    subgraph FirstAccess["On First Access"]
        E[Code calls All/ById/ByName] --> F[EnsureFrozen called]
        F --> G[_frozen = true]
        G --> H[Build FrozenDictionary]
        H --> I[Future RegisterMember throws]
    end

    BeforeAccess --> FirstAccess

Generated Registration Infrastructure

public partial class ConnectionStates
{
    // Pending registrations (mutable before freeze)
    private static readonly List<IConnectionState> _pendingRegistrations = new();
    private static readonly object _lock = new();
    private static volatile bool _frozen;
    private static FrozenDictionary<int, IConnectionState>? _all;

    // Static constructor registers compile-time discovered options
    static ConnectionStates()
    {
        RegisterMember(new OpenConnectionState());
        RegisterMember(new ClosedConnectionState());
        // ... other built-in states
    }

    // Called by module initializers for cross-assembly registration
    public static void RegisterMember(IConnectionState state)
    {
        if (_frozen)
            throw new InvalidOperationException("Collection is frozen");

        lock (_lock)
        {
            if (!_pendingRegistrations.Any(p => p.Id == state.Id))
                _pendingRegistrations.Add(state);
        }
    }

    // Called on first access
    private static void EnsureFrozen()
    {
        if (_all != null) return;
        lock (_lock)
        {
            _frozen = true;
            _all = _pendingRegistrations.ToFrozenDictionary(x => x.Id);
        }
    }

    public static FrozenDictionary<int, IConnectionState> All()
    {
        EnsureFrozen();
        return _all!;
    }
}

Module Initializers for NuGet Packages

For TypeOptions in separate NuGet packages, the Collections.SourceGenerators.Registration package generates module initializers in consuming assemblies:

// Generated in the consuming application
internal static class TypeOptionModuleInitializer
{
    [ModuleInitializer]
    internal static void RegisterTypeOptions()
    {
        // Register options from referenced packages
        ConnectionStates.RegisterMember(new CustomConnectionState());
    }
}

This runs before Main(), ensuring all options are registered before the collection is accessed.

For Package Authors

To enable transitive registration, embed the Registration generator in your package:

<ItemGroup>
  
  <None Include="$(OutputPath)FractalDataWorks.Collections.SourceGenerators.Registration.dll"
        Pack="true"
        PackagePath="analyzers/dotnet/cs" />
</ItemGroup>

See the Registration Generator README for complete details.

Advanced: Parent-Child Collections (TypeOption)

TypeCollections can be nested to create hierarchical collection structures using the TypeOption and TypeOptionName properties on the [TypeCollection] attribute.

Example: Roslyn Commands as Child of Development Commands

From RoslynCommands.cs:1-15:

using FractalDataWorks.Collections.Attributes;
using FractalDataWorks.Commands.Development.Abstractions;

namespace FractalDataWorks.Roslyn.Commands.Abstractions;

/// <summary>
/// Type collection for Roslyn commands.
/// Child collection of <see cref="DevelopmentCommands"/> for C# specific commands.
/// Discovers all commands marked with [TypeOption(typeof(RoslynCommands), "CommandName")].
/// </summary>
[TypeCollection(typeof(RoslynCommandBase), typeof(IRoslynCommand), typeof(RoslynCommands),
    TypeOption = typeof(DevelopmentCommands), TypeOptionName = "Roslyn")]
public static partial class RoslynCommands
{
}

How Parent-Child Works

  1. Parent Collection (DevelopmentCommands): Collects child collections as TypeOptions
  2. Child Collection (RoslynCommands): Has TypeOption and TypeOptionName set to register with parent
  3. The generator creates registration code so DevelopmentCommands.ByName("Roslyn") returns the RoslynCommands collection

Reference Architecture: ConnectionStates

For the definitive reference implementation, see the files in FractalDataWorks.Services.Connections.Abstractions:

This implementation demonstrates the complete, correct pattern.

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 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 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 (22)

Showing the top 5 NuGet packages that depend on FractalDataWorks.Collections:

Package Downloads
FractalDataWorks.Abstractions

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Configuration

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Commands.Abstractions

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Commands.Data.Abstractions

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Commands.Data

Development tools and utilities for the FractalDataWorks ecosystem. Build:

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.0-rc.1 84 2/9/2026
Loading failed