C# getting started

Build your first temporal comparison in .NET.

Start from an empty .NET 10 console application. The complete example records two providers' offline windows and compares them.

1. Create the project

Install Spanfold from NuGet.

dotnet new console --framework net10.0 --name SpanfoldQuickstart
cd SpanfoldQuickstart
dotnet add package Spanfold --version 0.1.0-preview.2

NuGet.org currently publishes 0.1.0-preview.2, so this journey uses that release's Spanfold.Spanfold.For<TEvent>() entry point. The repository's .NET source is versioned 0.2.0-preview.1 but is not yet published.

2. Add the example

Replace Program.cs.

Processing positions keep the first result easy to inspect: each ingested event advances the position by one.

using Spanfold;

var pipeline = Spanfold.Spanfold
    .For<DeviceStatus>()
    .RecordWindows()
    .TrackWindow(
        "DeviceOffline",
        key: status => status.DeviceId,
        isActive: status => !status.IsOnline);

Ingest("provider-a", isOnline: true);  // position 1
Ingest("provider-b", isOnline: true);  // position 2
Ingest("provider-a", isOnline: false); // position 3, A opens
Ingest("provider-b", isOnline: false); // position 4, B opens
Ingest("provider-b", isOnline: true);  // position 5, B closes
Ingest("provider-a", isOnline: true);  // position 6, A closes

var result = pipeline.History
    .Compare("Provider comparison")
    .Target("provider-a", selector => selector.Source("provider-a"))
    .Against("provider-b", selector => selector.Source("provider-b"))
    .Within(scope => scope.Window("DeviceOffline"))
    .Using(comparators => comparators.Overlap().Residual().Missing())
    .Run();

Console.WriteLine($"closed windows: {pipeline.History.ClosedWindows.Count}");
Console.WriteLine($"overlap rows: {result.OverlapRows.Count}");
Console.WriteLine($"provider-a-only rows: {result.ResidualRows.Count}");
Console.WriteLine($"provider-b-only rows: {result.MissingRows.Count}");

foreach (var row in result.OverlapRows)
{
    Console.WriteLine($"overlap {row.Key}: {row.Range.Start.Position}..{row.Range.End!.Value.Position}");
}

foreach (var row in result.ResidualRows)
{
    Console.WriteLine($"a-only {row.Key}: {row.Range.Start.Position}..{row.Range.End!.Value.Position}");
}

void Ingest(string source, bool isOnline)
{
    pipeline.Ingest(new DeviceStatus("device-17", isOnline), source);
}

public sealed record DeviceStatus(string DeviceId, bool IsOnline);

3. Run it

Inspect the comparison rows.

dotnet run
closed windows: 2
overlap rows: 1
provider-a-only rows: 2
provider-b-only rows: 0
overlap device-17: 4..5
a-only device-17: 3..4
a-only device-17: 5..6

Provider A was offline from position 3 to 6; provider B from 4 to 5. The result keeps the shared interval and both A-only intervals as separate rows.

4. Continue

Move from the first comparison to your own history.