Graphify 1.0.0-rc.13

This is a prerelease version of Graphify.
dotnet add package Graphify --version 1.0.0-rc.13
                    
NuGet\Install-Package Graphify -Version 1.0.0-rc.13
                    
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="Graphify" Version="1.0.0-rc.13">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Graphify" Version="1.0.0-rc.13" />
                    
Directory.Packages.props
<PackageReference Include="Graphify">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
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 Graphify --version 1.0.0-rc.13
                    
#r "nuget: Graphify, 1.0.0-rc.13"
                    
#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 Graphify@1.0.0-rc.13
                    
#: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=Graphify&version=1.0.0-rc.13&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Graphify&version=1.0.0-rc.13&prerelease
                    
Install as a Cake Tool

Graphify NuGet GitHub

Graphify is a .NET Roslyn source generator that turns your object models into navigable graphs. It enables engineers to scan an object hierarchy and observe values at different levels without reflection by generating strongly-typed nodes.

Why Graphify

  • Graph scanning without reflection: Traverse and observe your object graphs with generated, strongly-typed nodes.
  • Type-safe visitors: Register and compose visitors for specific nodes in the graph.
  • Generator-backed performance: Build-time code generation avoids runtime discovery costs.
  • Analyzer guardrails: Diagnostics catch misconfiguration early.

Requirements

  • .NET SDK with a Roslyn-capable compiler (Visual Studio 2022, Rider, or VS Code with the C# extension).
  • A C# language version that supports source generators and async streams (C# 8.0 or later).

Installation

Add the package reference to your project:

<ItemGroup>
  <PackageReference Include="Graphify" Version="<LATEST_VERSION>" />
</ItemGroup>

Or via the package manager console:

Install-Package Graphify

Quick Start

Annotate a partial type with the Graphify attribute to generate graph nodes and visitor hooks.

using Graphify;

[Graphify]
public sealed partial class Order
{
    public Customer Customer { get; init; } = new();

    public decimal Total { get; init; }
}

With generated graph nodes, you can register visitors for specific paths (for example, observing the Total or Customer) without using reflection. The generated APIs give you strongly-typed entry points into the object graph.

Key Concepts

Graphify generates a few key building blocks. Understanding these makes it easier to wire up scanning and observation in your application.

Model

The model is your domain object graph annotated with the Graphify attribute. Any public instance properties become navigation points in the graph. The model is generated within the scope of the annotated type, within a subclass named Graph. Each tier within the object graph is nested within the definition of the previous, providing an intuitive structure.

So when using Order as defined above and we define Customer as:

public sealed class Customer
{
    public string Email { get; init; } = string.Empty;

    public string Name { get; init; } = string.Empty;
}

Taking the Name node for brevity, the following structure is generated to allow observation:

partial class Order
{
    public sealed partial class Graph
    {
        public sealed partial class Customer
        {
            public sealed partial class Name
            {
                internal Name(Order root, Customer customer, string Value)
                {
                    Root = root;
                    Customer = customer;
                    Value = Value;
                }

                public Order Root { get; private set; }

                public Customer Customer { get; private set; }

                public string Value { get; private set; }
            }
        }
    }
}

Traverse

Use the Traverse attribute to control how Graphify walks specific properties. The Scope property defaults to TraverseScope.All, which behaves the same as if the attribute is not present. Set Scope to TraverseScope.None to exclude the property entirely, or to TraverseScope.Property to include the property itself while skipping any child properties (for collections, elements are still enumerated, but their child properties are not traversed).

public sealed class Customer
{
    [Traverse(Scope = TraverseScope.Property)]
    public Address Address { get; init; } = new();
}

Visitors

Visitors allows for the observation of specific nodes within the heirarchy. You implement a visitor by targeting the node type you care about and returning the appropriate observation(s). This makes it easy to capture the exact data points you need without manual tree-walking.

The following demonstrates a visitor that observes the Email value from the Customer node:

using Graphify;

public sealed class CustomerEmailVisitor(IBlacklist blacklist)
    : IVisitor<Order.Graph.Customer.Email>
{
    public async IAsyncEnumerable<string> Observe(Order.Graph.Customer.Email instance, [EnumeratorCancellation] CancellationToken cancellationToken))
    {
        if (blacklist.Contains(instance.Value))
        {
            yield return instance.Value;
        }
    }
}

The navigator is the generated entry point for scanning the graph. It coordinates traversal from the root node through child nodes, invoking any visitors registered for each node. Because the traversal logic is generated, there is no reflection and no runtime discovery cost. The navigator is specific to the type annotated with Graphify with an interface and implementation generated alongside the annotated type.

For the Order example, the following navigator interface will be IOrderNavigator with the internal implementation being OrderNavigator. The implementation uses the IServiceProvider to resolve visitors as it traverses the graph.

public sealed class OrderVerificationService(IOrderNavigator navigator)
{
    public async IAsyncEnumerable<string> Verify(Order[] orders, [EnumeratorCancellation] CancellationToken cancellationToken)
    {
        foreach (Order order in orders)
        {
            await foreach (string email in navigator.Navigate<string>(order, cancellationToken))
            {
                yield return email;
            }
        }
    }
}

IoC registration

Graphify generates an extension method to support registration of the navigator for dependency injection whenever the project within which the annotated type references IServiceCollection from Microsoft.Extensions.DependencyInjection. This allows you to compose the navigator with your existing application services and control their lifetime centrally.

For the Order example, the navigator can be registered as follows:

_ = services.AddOrderNavigator();

The service will be registered as a singleton on IOrderNavigator and INavigator<Order>.

Typical usage flow

  1. Annotate a Model with Graphify to generate the graph nodes and navigator.
  2. Register Navigator using the generated IoC extension methods.
  3. Implement Visitors for nodes you want to observe.
  4. Register Visitors using the same container that the navigator.
  5. Scan the Graph using the navigator to gather observations.

This flow keeps traversal explicit, type-safe, and discoverable in IntelliSense.

Analyzers

Graphify ships analyzers to keep your graph models consistent and safe:

Rule ID Category Severity Description
GRAFY01 Usage Warning Type is not compatible with Graphify
GRAFY02 Usage Warning Type is not Partial
GRAFY03 Usage Info Type does not utilize Graphify

Contributing

Contributions are welcome. See CONTRIBUTING.md for build instructions and coding guidelines.

License

This project is licensed under the MIT License. See LICENSE.md for details.

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

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-rc.13 64 2/10/2026