ObjectTreeWalker 0.12.5

dotnet add package ObjectTreeWalker --version 0.12.5
                    
NuGet\Install-Package ObjectTreeWalker -Version 0.12.5
                    
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="ObjectTreeWalker" Version="0.12.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ObjectTreeWalker" Version="0.12.5" />
                    
Directory.Packages.props
<PackageReference Include="ObjectTreeWalker" />
                    
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 ObjectTreeWalker --version 0.12.5
                    
#r "nuget: ObjectTreeWalker, 0.12.5"
                    
#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 ObjectTreeWalker@0.12.5
                    
#: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=ObjectTreeWalker&version=0.12.5
                    
Install as a Cake Addin
#tool nuget:?package=ObjectTreeWalker&version=0.12.5
                    
Install as a Cake Tool

Build & Test

ObjectGraphWalker

ObjectGraphWalker is a powerful utility library that enables seamless traversal over C# object properties and fields, Node.js style. Designed with performance and flexibility in mind, it leverages dynamic code generation and caching to provide efficient traversal capabilities.

Features

  • Fast Traversal: Utilizes dynamic code generation to create accessors that speed up traversal.
  • Flexible Filtering: Allows custom predicates to include or exclude specific members during traversal.
  • Support for Various Types: Works with both value and reference types, including generics and embedded structs.
  • Deep Cloning: Includes a high-performance deep clone extension method for complex object graphs.
  • Well-Tested: Includes comprehensive tests to ensure reliability and correctness.

Installation

Simply install the NuGet Package

Usage Examples

Simple Example

A basic example that demonstrates how to traverse an object and access its properties:

var someObject = new SomeObject();
var iterator = new ObjectMemberIterator();
iterator.Traverse(someObject, (in MemberAccessor accessor) =>
{
    var propertyValue = accessor.GetValue();
    prop.SetValue(/* some other value */);
});

Advanced Example

An advanced example that shows how to use predicates to filter members and control the traversal behavior:

var someObject = new SomeObject();
var iterator = new ObjectMemberIterator();
iterator.Traverse(someObject, (in MemberAccessor accessor) =>
{
    var propertyValue = accessor.GetValue();
    prop.SetValue(/* some other value */);

    //filtering for selective iteration is a simple lambda
}, (in MemberAccessor accessor) => accessor.Name != "Foo1" && accessor.MemberType != MemberType.Property);

Deep Cloning

You can easily create deep clones of any object using the provided extension method:

var someObject = new SomeObject();
var clone = someObject.DeepClone();

Performance

DeepClone() is benchmarked against AnyClone and DeepCloner using BenchmarkDotNet (bench/DeepCloneBenchmark, run with dotnet run --project bench/DeepCloneBenchmark -c Release):

Method Mean Allocated
ObjectTreeWalker - simple object 35.20 ns 32 B
DeepCloner - simple object 47.33 ns 168 B
AnyClone - simple object 661.65 ns 2624 B
ObjectTreeWalker - complex object 376.52 ns 568 B
DeepCloner - complex object 553.73 ns 1496 B
AnyClone - complex object 5,474.58 ns 17000 B

(Apple M2, .NET 10.0.9, results as of this writing - actual numbers will vary by machine.)

Notes

  • The iterator will read public and private properties and fields but will ignore any static members of the object.
  • The iterator will ignore backing fields for "auto properties" and any compiler-generated fields such as closures (unless specified in the constructor).
  • Traversal contract: collection members are expanded, never visited; collection items are reported as MemberType.CollectionItem and are read-only (SetValue on one throws InvalidOperationException); dictionary keys/values are flagged IsPartOfDictionary; an already-expanded instance reached again is reported once as a leaf and never re-expanded; struct TContext accumulates across collection recursion; a root string or other member-less leaf visits zero members.
  • KeyValuePair<K,V> members report Key/Value once; multidimensional array items use rank indices (M[0,1]); enum members are leaves.
  • By default a throwing member getter aborts the whole traversal; pass skipThrowingMembers: true to the ObjectMemberIterator constructor to skip such members instead.
  • DeepClone() supports arrays, dictionaries, IList/ICollection<T> collections, and plain objects. Compiler-generated iterator state machines (e.g. yield generators) throw NotSupportedException — materialize them into a List<T> or array first. Collection comparers are preserved when the type offers a matching constructor.
  • Long-lived hosts that see many dynamic or generic types can reclaim type-cache memory via ObjectEnumerator.ClearCache(), ObjectAccessor.ClearCache(), and ObjectExtensions.ClearCache().
  • While the iterator is well-tested, there may be some bugs. If you encounter any issues, please open an issue with a description.

Contributing

Any contributions are welcome 😃

License

MIT License

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 is compatible.  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 netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen 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 (3)

Showing the top 3 NuGet packages that depend on ObjectTreeWalker:

Package Downloads
RoguelikeToolkit.Entities

Package Description

DeepCloneBenchmark

Package Description

IteratorBenchmark

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.12.5 107 9/26/2026
0.12.3 208 3/16/2026
0.12.2 160 3/16/2026
0.11.1 576 4/25/2024
0.11.0 304 4/25/2024
0.10.18 899 8/21/2023
0.10.14 304 7/6/2023
0.10.13 375 5/27/2023
0.10.11 404 4/4/2023
0.10.8 624 1/14/2023
0.10.7 485 1/14/2023
0.10.5 483 12/25/2022
0.10.4 476 12/24/2022
0.10.3 2,240 12/3/2022
0.10.2 525 12/3/2022
0.9.4 501 11/29/2022
0.9.3 484 11/29/2022
0.9.2 672 11/7/2022
0.9.1 642 10/20/2022
0.9.0 619 10/19/2022
Loading failed

Changes since version v1.0.10.0

Fixed:
- Traversal no longer double-visits `KeyValuePair<K,V>` members (reports `Key`/`Value` once).
- Multidimensional array items now use rank indices (`M[0,1]`) instead of a flat position.
- Enum members are leaves (no more `value__` expansion), matching `DeepClone`.
- `DeepClone` of compiler-generated iterator state machines now throws `NotSupportedException` instead of producing a field-wise copy.
- `DeepClone` no longer copies framework collection internals (e.g. `ConcurrentDictionary` locks) and preserves extra state declared on intermediate bases (`A : B : List<int>`).
- `DeepClone` keeps the source comparer for collections without a pre-sizing constructor (e.g. `SortedSet<T>`).
- `MemberAccessor.SetValue` on a collection item now throws `InvalidOperationException` instead of silently ignoring the set.

Added:
- `ObjectMemberIterator(skipThrowingMembers: true)` skips members whose predicate or getter throws instead of aborting traversal.
- `ObjectAccessor.ClearCache()` and `ObjectExtensions.ClearCache()` for reclaiming type-cache memory in long-lived hosts; oversized pooled traversal queues are dropped instead of retained.