Skip to content

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.

  • GitHub stars for shinyorg/reflector
  • 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.Json converter 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
  1. Install the NuGet package:

    Terminal window
    dotnet add package Shiny.Reflector
  2. Add the [Reflector] attribute to your class and mark it as partial:

    using Shiny.Reflector;
    [Reflector]
    public partial class MyModel
    {
    public string Name { get; set; }
    public int? Age { get; set; }
    public DateTime CreatedAt { get; set; }
    }
  3. Use GetReflector() to access properties dynamically:

    var model = new MyModel { Name = "Hello", Age = 25 };
    var reflector = model.GetReflector();
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}");
}
// Typed access
var name = reflector.GetValue<string>("Name");
// Indexer access (case-insensitive)
var age = reflector["age"];
// Safe access with TryGet
if (reflector.TryGetValue<string>("Name", out var value))
Console.WriteLine($"Name = {value}");
// Typed setter
reflector.SetValue("Name", "Updated");
// Indexer setter
reflector["Age"] = 30;
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 are fully supported — just use partial and the attribute:

[Reflector]
public partial record MyRecord(string Name, int Age);