Reflection

Register the reflection tool suite to list registered roots, inspect live object state, describe runtime types, set writable members, and invoke reachable instance methods.

NuGet

Warning: This suite includes Critical tools and can inspect live runtime state, mutate writable members, or invoke reachable instance methods. Keep root registration, traversal boundaries, and write permissions narrowly scoped to local development workflows. You must not ever distribute these tools in a release build.

Install

dotnet add package Ansight.Tools.Reflection --prerelease

Register the Suite

using Ansight;
using Ansight.Tools.Reflection;

var session = new DebugSessionViewModel();

using var sessionRoot = ReflectionRootRegistry.Register(
    "session",
    session,
    new ReflectionRootMetadata("Current Session")
    {
        Description = "Active session view model",
        Hints = ["debug", "session"]
    },
    ReferenceType.Strong);

var options = Options.CreateBuilder()
    .WithReflectionTools(reflection =>
    {
        reflection.WithDefaultMemberVisibility(ReflectionMemberVisibility.PublicOnly);
        reflection.WithAssemblyTraversalMode(ReflectionAssemblyTraversalMode.AllowListedOnly);
        reflection.WithNamespaceTraversalMode(ReflectionNamespaceTraversalMode.AllowListedOnly);
        reflection.AllowNamespacePrefix("MyApp.ViewModels");
    })
    .WithReadWriteToolAccess()
    .Build();

Registration API

  • ReflectionRootRegistry.Register(string id, object target, ReflectionRootMetadata metadata, ReferenceType referenceType = ReferenceType.Weak): registers a live object root.
  • ReflectionRootRegistry.Register(string id, Func<object?> targetGetter, ReflectionRootMetadata metadata): registers a root that is resolved on each call.
  • ReflectionRootRegistry.Deregister(string id): removes the current root for an id.
  • ReflectionRootRegistrationHandle.Deregister() / Dispose(): removes the exact registration returned by Register(...).
  • WithReflectionTools(): registers the suite with default reflection options.
  • WithReflectionTools(reflection => ...): configures traversal and visibility while registering the suite.
  • WithReflectionTools(ReflectionToolsOptions): registers the suite with an options object.
  • WithAssemblyTraversalMode(...): choose AllowAll or AllowListedOnly for assembly-based traversal boundaries.
  • WithNamespaceTraversalMode(...): choose AllowAll or AllowListedOnly for namespace-based traversal boundaries.
  • AllowAssembly(...) / AllowAssemblies(...): add assembly allow-list entries when assembly traversal is AllowListedOnly.
  • AllowNamespacePrefix(...) / AllowNamespacePrefixes(...): add namespace-prefix allow-list entries when namespace traversal is AllowListedOnly.
  • WithDefaultMemberVisibility(...): set the global visibility rule. The default is PublicOnly.

The current simplified surface does not include per-root member or method allow-list APIs. Choose narrow roots, traversal boundaries, member visibility, and runtime guard policy instead.

Root Metadata

ReflectionRootMetadata requires DisplayName and also supports:

  • Description
  • Hints

Specific Concerns

  • The suite never reflects arbitrary process objects. Apps must register every root explicitly.
  • Direct object roots use weak references by default. Pass ReferenceType.Strong only when the root must stay alive for the lifetime of the suite.
  • Getter roots resolve the object every time a tool runs and report unavailable when the getter returns null or throws.
  • Expansion is stateless. Every call resolves from the root again rather than using persistent object handles.
  • Recursive traversal is open by default. Use AllowListedOnly traversal modes with AllowAssembly(...) and AllowNamespacePrefix(...) when you need to restrict expansion.
  • Types outside configured allow-list boundaries return opaque previews instead of recursive members.
  • Non-public members stay hidden unless you opt into ReflectionMemberVisibility.PublicAndNonPublic.
  • Reads are controlled by root registration, traversal boundaries, and member visibility. You do not need a separate read allow-list.
  • reflect.set_member_value and reflect.invoke_method are Write tools. They require WithReadWriteToolAccess() or a custom ToolGuard.
  • Writes still require the target field or property to be writable.
  • Collection-element writes and static method invocation are out of scope in v1.

If you want restricted traversal within registered roots, opt in explicitly:

reflection.WithAssemblyTraversalMode(ReflectionAssemblyTraversalMode.AllowListedOnly);
reflection.WithNamespaceTraversalMode(ReflectionNamespaceTraversalMode.AllowListedOnly);
reflection.AllowAssembly("MyApp");
reflection.AllowNamespacePrefix("MyApp.ViewModels");

Path Syntax

  • Property.SubProperty
  • [index]
  • ["key"]

Tool Matrix

NameIdScopeDescriptionSecurity
List Reflection Rootsreflect.list_rootsReadLists registered live object roots, metadata, and availability.High
Inspect Objectreflect.inspect_objectReadReturns a stateless snapshot of a registered live object or nested path.Critical
Describe Typereflect.describe_typeReadReturns runtime type metadata without reading live object values.Moderate
Set Member Valuereflect.set_member_valueWriteWrites a settable field or property reachable from a registered root.Critical
Invoke Methodreflect.invoke_methodWriteInvokes an instance method reachable from a registered root.Critical

List Reflection Roots

Arguments:

  • none

Returns:

  • roots
  • count
  • capturedAtUtc

Each root descriptor includes:

  • id
  • metadata
  • referenceType
  • available
  • runtimeType
  • memberVisibility
  • resolutionError

Example:

{
  "toolId": "reflect.list_roots",
  "arguments": {}
}

Inspect Object

Arguments:

  • root: required registered root id
  • path: optional nested member or collection path
  • maxDepth: recursive expansion depth, default 1, maximum 4
  • maxItemsPerCollection: collection item limit, default 10, maximum 64

Returns:

  • root
  • path
  • snapshot
  • capturedAtUtc

Snapshot payloads include common fields such as:

  • declaredType
  • runtimeType
  • kind
  • isNull
  • preview
  • expandable

Expanded snapshots may also include:

  • members
  • methods
  • items
  • truncated
  • opaque
  • cycleDetected

Example:

{
  "toolId": "reflect.inspect_object",
  "arguments": {
    "root": "session",
    "path": "Items[1]",
    "maxDepth": 2,
    "maxItemsPerCollection": 10
  }
}

Describe Type

Arguments:

  • typeName: required runtime type name
  • assemblyName: optional assembly name

Returns:

  • typeName
  • assemblyName
  • namespace
  • kind
  • baseType
  • interfaces
  • genericArity
  • memberVisibility
  • members
  • methods
  • capturedAtUtc

Example:

{
  "toolId": "reflect.describe_type",
  "arguments": {
    "typeName": "MyApp.DebugSessionViewModel",
    "assemblyName": "MyApp"
  }
}

Set Member Value

Arguments:

  • root: required registered root id
  • path: required member path
  • valueJson: required JSON-encoded replacement value

Returns:

  • root
  • path
  • updated
  • snapshot
  • capturedAtUtc

The write path must end on a settable field or property. Collection-element writes such as Items[0] are not supported.

Example:

{
  "toolId": "reflect.set_member_value",
  "arguments": {
    "root": "session",
    "path": "SelectedTab",
    "valueJson": "\"details\""
  }
}

Invoke Method

Arguments:

  • root: required registered root id
  • targetPath: optional nested target path
  • method: required method name
  • parameterTypesJson: optional JSON array of parameter type names for overload disambiguation
  • argumentsJson: optional JSON array of argument values

Returns:

  • root
  • targetPath
  • signature
  • invoked
  • returnSnapshot
  • capturedAtUtc

Overloaded methods require parameterTypesJson. Nested targets use the same path grammar as reflect.inspect_object.

Example:

{
  "toolId": "reflect.invoke_method",
  "arguments": {
    "root": "session",
    "targetPath": "Child",
    "method": "Rename",
    "parameterTypesJson": "[\"System.String\"]",
    "argumentsJson": "[\"Updated Child\"]"
  }
}