Reflector
Reflection is powerful but slow, and it breaks AOT compilation. Shiny Reflector uses C# source generators to give you the same dynamic property access — without any runtime reflection. Just add an attribute, mark your class partial, and you get compile-time generated property enumeration, reading, writing, and JSON serialization.
Features
Section titled “Features”- Enumerate properties with metadata (name, type, has setter)
- Read and write values using string keys — case-insensitive
- Indexer syntax for loose-typed access (
reflector["MyProperty"] = 123) - Built-in
System.Text.Jsonconverter for reflection-free serialization - Automatic fallback to true reflection for non-attributed types
- Assembly info generation — capture build variables as compile-time constants
- Works with classes, records, and MVVM Community Toolkit source generation
-
Install the NuGet package:
Terminal window dotnet add package Shiny.Reflector -
Add the
[Reflector]attribute to your class and mark it aspartial:using Shiny.Reflector;[Reflector]public partial class MyModel{public string Name { get; set; }public int? Age { get; set; }public DateTime CreatedAt { get; set; }} -
Use
GetReflector()to access properties dynamically:var model = new MyModel { Name = "Hello", Age = 25 };var reflector = model.GetReflector();
Using the Reflector
Section titled “Using the Reflector”Property Enumeration
Section titled “Property Enumeration”var reflector = model.GetReflector();
foreach (var prop in reflector.Properties){ var value = reflector[prop.Name]; Console.WriteLine($"{prop.Name} ({prop.Type.Name}) HasSetter={prop.HasSetter} Value={value}");}Reading Values
Section titled “Reading Values”// Typed accessvar name = reflector.GetValue<string>("Name");
// Indexer access (case-insensitive)var age = reflector["age"];
// Safe access with TryGetif (reflector.TryGetValue<string>("Name", out var value)) Console.WriteLine($"Name = {value}");Writing Values
Section titled “Writing Values”// Typed setterreflector.SetValue("Name", "Updated");
// Indexer setterreflector["Age"] = 30;Dynamic Property Copying
Section titled “Dynamic Property Copying”var source = sourceObject.GetReflector();var target = targetObject.GetReflector();
foreach (var prop in source.Properties){ if (target.HasProperty(prop.Name)) target.TrySetValue(prop.Name, source[prop.Name]);}Records
Section titled “Records”Records are fully supported — just use partial and the attribute:
[Reflector]public partial record MyRecord(string Name, int Age);