com.IvanMurzak.ReflectorNet 5.4.0

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

ReflectorNet

NuGet netstandard2.1 .NET 8.0 .NET 9.0 Tests

Stars Discord License Stand With Ukraine

ReflectorNet is a .NET reflection toolkit for dynamic automation, AI-assisted tooling, testing, and runtime inspection. It can serialize live objects with type metadata, deserialize them back, modify existing instances in place, inspect object graphs by path or pattern, generate JSON Schema, and discover or invoke methods from partial runtime descriptions.

The main entry point is Reflector. The central data model is SerializedMember, a JSON-friendly representation of a .NET value that preserves the member name, resolved type, fields, properties, and raw JSON value payload.

Index

Why ReflectorNet

Standard reflection is powerful, but it is low-level. ReflectorNet wraps reflection in higher-level operations that are useful when the caller does not have a compiled, strongly typed integration path.

Key capabilities:

  • Type-preserving serialization through SerializedMember.
  • Full object reconstruction with flexible type resolution.
  • In-place object modification without replacing the root reference.
  • Path-based reads and writes for fields, properties, list items, array items, and dictionary entries.
  • JSON Merge Patch style updates for multi-field modifications.
  • Regex-based object graph search with Grep.
  • JSON Schema generation for types, method arguments, and method return values.
  • Fuzzy method discovery and dynamic invocation through MethodRef and MethodCall.
  • Extensible reflection and JSON converter registries.
  • Optional type blacklisting for excluding unsafe, irrelevant, or expensive types from reflection workflows.

Installation

dotnet add package com.IvanMurzak.ReflectorNet

Target Frameworks

The library targets:

  • netstandard2.1
  • net8.0
  • net9.0

The test suite targets net8.0 and net9.0.

Quick Start

using System.Collections.Generic;
using com.IvanMurzak.ReflectorNet;
using com.IvanMurzak.ReflectorNet.Model;
using com.IvanMurzak.ReflectorNet.Utils;

var reflector = new Reflector();

var player = new PlayerState
{
    Name = "Ada",
    Level = 7,
    Inventory = new Inventory
    {
        Items = new List<ItemStack>
        {
            new ItemStack { ItemId = "health_potion", Quantity = 3 }
        }
    }
};

SerializedMember snapshot = reflector.Serialize(player);
PlayerState? copy = reflector.Deserialize<PlayerState>(snapshot);

object? liveObject = player;
var logs = new Logs();

reflector.TryModifyAt<int>(
    ref liveObject,
    "Inventory/Items/[0]/Quantity",
    10,
    logs: logs);

reflector.TryReadAt(
    liveObject,
    "Inventory/Items/[0]/Quantity",
    out SerializedMember? quantity);

Console.WriteLine(quantity?.GetValue<int>(reflector));

public sealed class PlayerState
{
    public string Name { get; set; } = string.Empty;
    public int Level { get; set; }
    public Inventory Inventory { get; set; } = new Inventory();
}

public sealed class Inventory
{
    public List<ItemStack> Items { get; set; } = new List<ItemStack>();
}

public sealed class ItemStack
{
    public string ItemId { get; set; } = string.Empty;
    public int Quantity { get; set; }
}

Core Features

Type-Preserving Serialization

Reflector.Serialize turns a live object into a SerializedMember. For complex objects, fields and properties are represented as nested SerializedMember entries. Primitive and converter-backed values are stored in the value JSON payload.

var data = reflector.Serialize(player, name: "player");
string json = reflector.JsonSerializer.Serialize(data);

Reflector.Deserialize reconstructs the object from that representation.

var restored = reflector.Deserialize<PlayerState>(data);

ReflectorNet also tracks visited objects during serialization and can emit $ref entries for repeated references, helping avoid endless recursion in cyclic object graphs.

In-Place Modification

TryModify applies a SerializedMember onto an existing object instance.

object? target = player;
var patch = new SerializedMember
{
    typeName = typeof(PlayerState).GetTypeId()
};

patch.SetPropertyValue(reflector, "Level", 8);

bool ok = reflector.TryModify(ref target, patch, logs: logs);

This is useful for stateful systems such as games, editors, services, and test harnesses where keeping object identity matters.

Path Syntax

Path-based APIs use slash-delimited paths:

Segment Meaning Example
Name Field or property Inventory
[0] Array or IList index Items/[0]
[key] Dictionary key Settings/[timeout]

A leading #/ is accepted and stripped, which makes paths compatible with SerializationContext reference paths.

Object Inspection

TryReadAt

TryReadAt navigates to one value and serializes only that target.

if (reflector.TryReadAt(player, "Inventory/Items/[0]/ItemId", out var itemId))
{
    Console.WriteLine(itemId!.GetValue<string>(reflector));
}

Invalid paths return false and write details into Logs when supplied.

View

View returns a serialized tree for the whole object or a navigated subtree, with optional filters.

SerializedMember? view = reflector.View(player, new ViewQuery
{
    Path = "Inventory",
    NamePattern = "Item|Quantity",
    MaxDepth = 3
});

ViewQuery supports:

Option Description
Path Navigate before serialization.
MaxDepth Limit the returned tree depth. 0 returns only the root envelope.
NamePattern Case-insensitive .NET regex matched against field and property names.
TypeFilter Keep branches whose resolved type is assignable to the supplied Type.

When filters match nothing, View keeps the root envelope so callers still know what object type was inspected.

Grep

Grep searches the live object graph for matching field or property names and returns flat path/value matches.

IReadOnlyList<ViewMatch> matches = reflector.Grep(player, "^Quantity$");

foreach (var match in matches)
{
    Console.WriteLine($"{match.Path}: {match.Value.GetValue<int>(reflector)}");
}

Use Grep when you need to search inside arrays or lists. View filters the serialized tree; Grep walks the live object graph.

Object Modification

TryModifyAt

TryModifyAt changes one target path without touching sibling values.

object? target = player;

reflector.TryModifyAt<int>(
    ref target,
    "Inventory/Items/[0]/Quantity",
    12,
    logs: logs);

The same path syntax works for object members, lists, arrays, and dictionaries. For dictionaries, missing keys can be added when the key can be converted to the dictionary key type.

You can also apply a partial SerializedMember to a complex node:

var itemPatch = new SerializedMember
{
    typeName = typeof(ItemStack).GetTypeId()
};

itemPatch.SetPropertyValue(reflector, "Quantity", 20);

reflector.TryModifyAt(
    ref target,
    "Inventory/Items/[0]",
    itemPatch,
    logs: logs);

TryPatch

TryPatch applies a JSON Merge Patch style document. It is useful when multiple values need to be updated in one call.

reflector.TryPatch(ref target, """
{
  "Level": 9,
  "Inventory": {
    "Items": {
      "[0]": {
        "Quantity": 15
      }
    }
  }
}
""", logs: logs);

Patch behavior:

  • JSON object keys navigate into fields, properties, array/list indexes, or dictionary keys.
  • JSON scalar values set the current value.
  • null sets the current value to null when the target type allows it.
  • $type can request a compatible subtype replacement before applying the remaining keys.
  • Invalid JSON, unknown members, incompatible type hints, read-only properties, and failed key conversions return false and are reported through Logs.

Dynamic Method Workflows

Find Methods

FindMethod searches loaded assemblies for methods matching a MethodRef. Matching can be exact or fuzzy.

using com.IvanMurzak.ReflectorNet.Model;

var filter = new MethodRef
{
    Namespace = typeof(PlayerCommands).Namespace,
    TypeName = "PlayerCommands",
    MethodName = "GrantItem"
};

var methods = reflector.FindMethod(
    filter,
    knownNamespace: true,
    typeNameMatchLevel: 6,
    methodNameMatchLevel: 6);

String match levels:

Level Match
6 Exact, case-sensitive
5 Exact, case-insensitive
4 Prefix, case-sensitive
3 Prefix, case-insensitive
2 Contains, case-sensitive
1 Contains, case-insensitive
0 Disabled

Parameter matching can also be enabled with parametersMatchLevel.

Invoke Methods

MethodCall combines method discovery, parameter deserialization, target instance handling, invocation, and JSON result formatting.

var args = new SerializedMemberList
{
    reflector.Serialize("health_potion", name: "itemId"),
    reflector.Serialize(2, name: "quantity")
};

string result = reflector.MethodCall(
    reflector,
    new MethodRef
    {
        TypeName = "PlayerCommands",
        MethodName = "GrantItem"
    },
    inputParameters: args,
    executeInMainThread: false);

For instance methods, pass targetObject as a serialized object. If no target is supplied, ReflectorNet attempts to create an instance of the declaring type.

JSON Schema Generation

ReflectorNet can generate JSON Schema for types and methods. This is especially useful for AI function calling, tooling UIs, runtime validation, and API documentation.

using System.Reflection;

var typeSchema = reflector.GetSchema<PlayerState>();
var typeRef = reflector.GetSchemaRef<PlayerState>();

MethodInfo method = typeof(PlayerCommands).GetMethod(nameof(PlayerCommands.GrantItem))!;

var inputSchema = reflector.GetArgumentsSchema(method);
var outputSchema = reflector.GetReturnSchema(method);

Schema generation supports:

  • Fields and properties discovered through the reflection converter chain.
  • Primitive, collection, dictionary, generic, and nested types.
  • $defs reuse for complex types.
  • Nullable and optional method parameter handling.
  • Return type unwrapping for Task<T> and ValueTask<T>.
  • Descriptions from DescriptionAttribute.
  • Custom schema output through IJsonSchemaConverter.

Converters and Extensibility

ReflectorNet uses a priority-based converter registry. Each IReflectionConverter reports how well it can handle a type, and the registry selects the highest-priority converter.

Default reflection converters include:

  • PrimitiveReflectionConverter for primitive and common value types.
  • ArrayReflectionConverter for arrays and list-like collections.
  • GenericReflectionConverter<object> for ordinary classes and structs.
  • TypeReflectionConverter for System.Type.
  • AssemblyReflectionConverter for System.Reflection.Assembly.

Register a reflection converter when a type needs custom object traversal, creation, or mutation behavior:

using com.IvanMurzak.ReflectorNet.Converter;

reflector.Converters.Add(new MyReflectionConverter());

Register a JSON converter when a type needs custom JSON transport or schema behavior:

reflector.JsonSerializer.AddConverter(new MyJsonConverter());

Useful built-in extension points:

  • GenericReflectionConverter<T> for normal custom object handling.
  • LazyGenericReflectionConverter for optional runtime dependencies resolved by type name.
  • IgnoreFieldsAndPropertiesReflectionConverter<T> for treating selected types as shallow or read-only.
  • IJsonSchemaConverter and JsonSchemaConverter<T> for custom JSON Schema definitions.

Types can be excluded from reflection processing through the registry blacklist:

reflector.Converters.BlacklistType(typeof(ExpensiveRuntimeType));
reflector.Converters.BlacklistTypes("Some.Namespace.InternalType");
reflector.Converters.BlacklistTypeInAssembly("MyCompany.Game", "MyCompany.Game.SecretState");

Blacklist checks include inheritance, implemented interfaces, arrays, and generic type arguments.

Project Layout

ReflectorNet/
  ReflectorNet/                    Main library project
  ReflectorNet.Tests/              xUnit tests
  ReflectorNet.Tests.OuterAssembly/ Cross-assembly test models
  ConsoleApp/                      Manual schema and behavior checks
  docs/                            Maintainer notes and architecture documentation
  commands/                        Release and version helper scripts

Important library areas:

  • src/Reflector/ contains the Reflector partial class split by responsibility.
  • src/Model/ contains SerializedMember, SerializedMemberList, MethodRef, MethodData, Logs, and view models.
  • src/Converter/Reflection/ contains the reflection converter chain.
  • src/Converter/Json/ contains System.Text.Json converters and schema-aware converters.
  • src/Utils/Json/ contains JSON serialization and schema generation utilities.

Development

Restore and build:

dotnet restore
dotnet build ReflectorNet.sln

Run tests:

dotnet test ReflectorNet.sln

Create a NuGet package locally:

dotnet pack ReflectorNet/ReflectorNet.csproj -c Release

License

ReflectorNet is licensed under the Apache License 2.0. See LICENSE for details.

Copyright (c) Ivan Murzak.

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 is compatible.  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 is compatible.  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 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 (14)

Showing the top 5 NuGet packages that depend on com.IvanMurzak.ReflectorNet:

Package Downloads
com.IvanMurzak.McpPlugin.Common

McpPlugin common code for McpPlugin and McpPlugin.Server projects. It is .NET Library project for integration MCP server features into any dotnet application. It connects automatically with MCP server and exposes it's API over TCP connection in runtime. When MCP server interacts with AI.

com.IvanMurzak.McpPlugin

McpPlugin is a .NET Library project for integration MCP server features into any dotnet application. It connects automatically with MCP server and exposes it's API over TCP connection in runtime. When MCP server interacts with AI. This library maintains a local application.

com.IvanMurzak.McpPlugin.Server

MCP Server dotnet. Model Context Protocol server that interacts with MCP Plugin integrated into any dotnet application.

com.IvanMurzak.Unity.MCP.Common

Shared code between Unity-MCP-Plugin and Unity-MCP-Server projects.

com.IvanMurzak.Godot.MCP.PhantomCamera

AI MCP tools for Godot PhantomCamera.

GitHub repositories (2)

Showing the top 2 popular GitHub repositories that depend on com.IvanMurzak.ReflectorNet:

Repository Stars
IvanMurzak/Unity-MCP
AI Skills, MCP Tools, and CLI for Unity Engine. Full AI develop and test loop. Use cli for quick setup. Efficient token usage, advanced tools. Any C# method may be turned into a tool by a single line. Works with Claude Code, Gemini, Copilot, Cursor and any other absolutely for free.
IvanMurzak/Godot-MCP
Godot-MCP — Model Context Protocol (MCP) integration for the Godot Engine. AI tools for the Godot Editor in C#, with cloud connection to ai-game.dev. Apache-2.0.
Version Downloads Last Updated
5.4.0 3,260 7/28/2026
5.3.3 367 7/27/2026
5.3.2 9,470 7/11/2026
5.3.1 20,646 6/2/2026
5.3.0 417 6/2/2026
5.2.0 3,603 5/27/2026
5.1.2 2,586 5/21/2026
5.1.1 8,943 4/29/2026
5.1.0 457 4/29/2026
5.0.0 6,948 4/16/2026
4.1.0 1,096 3/25/2026
4.0.0 2,354 3/3/2026
3.12.1 1,480 2/12/2026
3.12.0 722 1/31/2026
3.11.0 624 1/20/2026
3.10.0 545 1/19/2026
3.9.0 527 1/18/2026
3.8.1 508 1/18/2026
3.8.0 520 1/18/2026
3.7.1 564 1/17/2026
Loading failed