ScottEncodingGenerator 1.0.0
dotnet add package ScottEncodingGenerator --version 1.0.0
NuGet\Install-Package ScottEncodingGenerator -Version 1.0.0
<PackageReference Include="ScottEncodingGenerator" Version="1.0.0" />
<PackageVersion Include="ScottEncodingGenerator" Version="1.0.0" />
<PackageReference Include="ScottEncodingGenerator" />
paket add ScottEncodingGenerator --version 1.0.0
#r "nuget: ScottEncodingGenerator, 1.0.0"
#:package ScottEncodingGenerator@1.0.0
#addin nuget:?package=ScottEncodingGenerator&version=1.0.0
#tool nuget:?package=ScottEncodingGenerator&version=1.0.0
ScottEncodingGenerator
ScottEncodingGenerator is a C# source generator for defining closed sets of nested case types and generating a Match API for them.
It targets types marked with [ScottEncoding] and generates:
- a
Match<TResult>(...)member on the target type - per-case
Matchimplementations on nested case types - factory methods for constructing cases
- step-by-step extension methods for building a full match expression
The generator supports:
partial interfacetargetsabstract partial classtargets
It does not support:
- structs as targets
- generic nested cases
- non-partial nested cases
Purpose
The generator is intended for code shaped like a discriminated union encoded with nested types.
Instead of manually writing:
- the common
Matchcontract - one implementation per case
- helper factory methods
- fluent matching helpers
the generator derives those from the target type and its nested case declarations.
Example
Input
[ScottEncoding]
public abstract partial class Option<T>
{
public sealed partial class Some
{
public Some(T value) => Value = value;
public T Value { get; }
}
public sealed partial class None
{
public None() { }
}
}
Generated shape
The generator adds a Match member to the target:
public abstract partial class Option<T>
{
public abstract TResult Match<TResult>(
Func<Option<T>.Some, TResult> some,
Func<Option<T>.None, TResult> none);
public sealed partial class Some : Option<T>
{
public override TResult Match<TResult>(
Func<Option<T>.Some, TResult> some,
Func<Option<T>.None, TResult> none)
=> some(this);
}
public sealed partial class None : Option<T>
{
public override TResult Match<TResult>(
Func<Option<T>.Some, TResult> some,
Func<Option<T>.None, TResult> none)
=> none(this);
}
}
It also generates a companion helper type:
public static partial class OptionModule
{
public static Option<T> Some<T>(T value) => new Option<T>.Some(value);
public static Option<T> None<T>() => new Option<T>.None();
public static MatchStep2<T, TResult> IfSome<T, TResult>(
this Option<T> value,
Func<Option<T>.Some, TResult> some)
=> new(value, some);
}
Usage:
Option<int> x = OptionModule.Some(10);
var text = x.Match(
some => $"Some({some.Value})",
none => "None");
Or with the generated step API:
var text = x
.IfSome(some => $"Some({some.Value})")
.IfNone(_ => "None");
Interface targets
The generator also supports interface targets.
Input
[ScottEncoding]
public partial interface Expr
{
public sealed partial class Constant
{
public Constant(int value) => Value = value;
public int Value { get; }
}
public sealed partial class Add
{
public Add(Expr left, Expr right)
{
Left = left;
Right = right;
}
public Expr Left { get; }
public Expr Right { get; }
}
}
Generated shape
For interfaces, the generator emits:
- a
Match<TResult>(...)declaration on the interface - nested case classes implementing the interface
- helper factories in
ExprModule
Example use:
Expr expr = ExprModule.Add(
ExprModule.Constant(1),
ExprModule.Constant(2));
var value = expr.Match(
constant => constant.Value,
add => add.Left.Match(
l => l.Value,
_ => 0) +
add.Right.Match(
r => r.Value,
_ => 0));
Rules
A target type must:
be marked with
[ScottEncoding]be
partialbe either:
- an
abstract partial class, or - a
partial interface
- an
A nested case type must:
- be declared inside the target
- be a non-generic class
- be
partial - be non-abstract
- expose at least one accessible instance constructor
For class targets, a nested case may:
- omit an explicit base type, or
- inherit from the target type
For interface targets, a nested case may:
- omit an explicit base type, or
- implement the target interface
A nested case must not specify an unrelated base type.
Factories
For each accessible constructor on each case, the generator emits a factory method in <TargetName>Module.
Example:
public sealed partial class Error
{
public Error(string message) => Message = message;
public string Message { get; }
}
Generates a factory similar to:
public static Result<T> Error<T>(string message) => new Result<T>.Error(message);
If a case has multiple accessible constructors, additional factory methods are emitted with suffixes derived from constructor parameters or an index.
Matching API
The generated Match<TResult>(...) method takes one delegate per case, in declaration order.
For a target with cases:
SuccessFailureLoading
the generated signature is shaped like:
TResult Match<TResult>(
Func<Success, TResult> success,
Func<Failure, TResult> failure,
Func<Loading, TResult> loading);
The fluent step API follows the same order:
value
.IfSuccess(...)
.IfFailure(...)
.IfLoading(...);
Diagnostics
The generator reports the following diagnostics.
SCOTT001
Target is not valid.
Raised when the target is not:
- partial
- an interface
- or an abstract class
SCOTT002
No valid cases were found.
Raised when the target does not declare any usable nested case types.
SCOTT003
A nested case has an invalid shape.
Raised when a case is not a:
- partial class
- non-generic class
- non-abstract class
SCOTT004
A nested case has no accessible instance constructor.
SCOTT005
A nested case has an invalid relationship to the target.
Raised when a case declares an unrelated base type.
SCOTT006
The target already declares a conflicting Match method.
Generated files
The generator emits:
ScottEncodingAttribute.g.cs- one generated file per valid target, named from the target symbol
The generated code enables nullable references with:
#nullable enable
Notes
- Cases are processed in a stable order based on syntax location.
- The helper type is named
<TargetName>Module. - The helper type is generated as
static partial. - Matching delegates use fully qualified type names in generated code.
- The generated API preserves target type parameters and constraint clauses.
Minimal example
[ScottEncoding]
public abstract partial class BoolLike
{
public sealed partial class True
{
public True() { }
}
public sealed partial class False
{
public False() { }
}
}
Usage:
BoolLike value = BoolLikeModule.True();
var result = value.Match(
@true => 1,
@false => 0);
| Product | Versions 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. |
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 4.3.0)
- Microsoft.CodeAnalysis.CSharp.Workspaces (>= 4.3.0)
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.0 | 116 | 4/3/2026 |