Visitor.NET 3.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Visitor.NET --version 3.0.0
NuGet\Install-Package Visitor.NET -Version 3.0.0
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="Visitor.NET" Version="3.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Visitor.NET --version 3.0.0
#r "nuget: Visitor.NET, 3.0.0"
#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.
// Install Visitor.NET as a Cake Addin
#addin nuget:?package=Visitor.NET&version=3.0.0

// Install Visitor.NET as a Cake Tool
#tool nuget:?package=Visitor.NET&version=3.0.0

Status:

NuGet

Visitor.NET

With Visitor.NET you can develop typesafe acyclic visitors even if you do not have access to source code of visitable structures.

Installation

NuGet

Install package : https://www.nuget.org/packages/Visitor.NET.

GitHub

  • Clone locally this github repository
  • Build the Visitor.NET.sln solution

Usage

Basic Example

Let's say we have some expression-tree-like hierarchy, implementing basic arithmetics, like this:

public abstract record BinaryTreeNode;

public record Operation(char Symbol, BinaryTreeNode Left, BinaryTreeNode Right) : BinaryTreeNode;

public record Number(double Value) : BinaryTreeNode;

public record Parenthesis(BinaryTreeNode Node) : BinaryTreeNode;

So we may want to traverse it in order to, for example, compute expression result.

First of all, we implement evaluator using IVisitor<,> interface:

public class BinaryTreeEvaluator :
    IVisitor<Operation, double>,
    IVisitor<Number, double>,
    IVisitor<Parenthesis, double>
{
    public double Visit(Operation visitable) =>
        visitable.Symbol switch
        {
            '+' => visitable.Left.Accept(this) + visitable.Right.Accept(this),
            _ => throw new NotImplementedException()
        };

    public double Visit(Number visitable) => visitable.Value;

    public double Visit(Parenthesis visitable) => visitable.Node.Accept(this);
}

But then we have to tell structures we visit that they are visitable.

It is done through IVisitable<,> interface implementation:

public abstract record BinaryTreeNode : 
    IVisitable<BinaryTreeEvaluator, double>
{
    public abstract double Accept(BinaryTreeEvaluator visitor);
}

public record Operation(char Symbol, BinaryTreeNode Left, BinaryTreeNode Right) : BinaryTreeNode
{
    public override double Accept(BinaryTreeEvaluator visitor) =>
        visitor.Visit(this);
}

public record Number(double Value) : BinaryTreeNode
{
    public override double Accept(BinaryTreeEvaluator visitor) =>
        visitor.Visit(this);
}

public record Parenthesis(BinaryTreeNode Node) : BinaryTreeNode
{
    public override double Accept(BinaryTreeEvaluator visitor) =>
        visitor.Visit(this);
}

Basically, if you have access to source code of structure you want "visit", it's better to always have implementation:

return visitor.Visit(this);

In case you would make Visit implementation procedure (i.e. have no returning value), use Unit type as return type.

So, your method would look like this:

public class SomeVisitor : IVisitor<Some>
{
    public Unit Visit(Some visitable)
    {
        //...
        return default;
    }
}

Adapter Usage

Let's imagine you want to visit some structure defined outside of your project (library, dto, etc.):

public record LinkedListNode<T>(T Data, LinkedListNode<T> Next)
{
    public bool HasNext() => Next != null;
}

So we may define wrapper around instance of this type which would became visitable:

public class LinkedListToVisitableAdapter<T> : 
    VisitableAdapter<LinkedListNode<T>, LinkedListNodePrinter<T>>
{
    public LinkedListToVisitableAdapter(LinkedListNode<T> data) : base(data)
    {
    }

    public override Unit Accept(LinkedListNodePrinter<T> visitor) =>
        visitor.Visit(this);
}

This adapter can be instantiated with VisitableAdapterFactory<,,> implementation:

public class LinkedListToVisitableAdapterFactory<T> :
    VisitableAdapterFactory<LinkedListNode<T>, LinkedListNodePrinter<T>>
{
    public override LinkedListToVisitableAdapter<T> Create(LinkedListNode<T> data) =>
        new(data);
}

Bringing it all together:

public class LinkedListNodePrinter<T> : IVisitor<LinkedListToVisitableAdapter<T>>
{
    private readonly StringBuilder _sb = new();
    private readonly VisitableAdapterFactory<LinkedListNode<T>, LinkedListNodePrinter<T>> _factory;

    public LinkedListNodePrinter(VisitableAdapterFactory<LinkedListNode<T>, LinkedListNodePrinter<T>> factory)
    {
        _factory = factory;
    }

    public Unit Visit(LinkedListToVisitableAdapter<T> visitable)
    {
        var node = visitable.Data;
        _sb.Append(node.Data);
        if (node.HasNext())
        {
            var next = _factory.Create(node.Next);
            _sb.Append("->");
            next.Accept(this);
        }

        return default;
    }

    public override string ToString() => _sb.ToString();
}
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

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
4.0.0 128 12/11/2023
3.0.0 180 5/2/2023
2.0.0 503 8/22/2022
1.0.0 503 7/28/2022