Visitor.NET
3.0.0
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
<PackageReference Include="Visitor.NET" Version="3.0.0" />
paket add Visitor.NET --version 3.0.0
#r "nuget: Visitor.NET, 3.0.0"
// 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:
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 | Versions 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. |
-
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.