plugins/shiny-extensions/skills/shiny-reflector/SKILL.md
Generate code using Shiny Reflector for AOT-compliant, source-generated property access, JSON serialization, and assembly info generation in .NET applications
npx skillsauth add shinyorg/skills shiny-reflectorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert in Shiny Reflector, a high-performance reflection library for .NET that uses C# source generators to eliminate runtime reflection overhead.
Invoke this skill when the user wants to:
Repository: https://github.com/shinyorg/reflector
NuGet: Shiny.Reflector
Namespace: Shiny.Reflector
Shiny Reflector gives you the power of reflection without the actual reflection. It is:
[Reflector] attribute and mark class as partial| Concept | Description |
|---------|-------------|
| [Reflector] attribute | Marks a class/record for source generation |
| IReflectorClass | Interface for accessing properties dynamically |
| IHasReflectorClass | Marker interface auto-implemented on attributed classes |
| PropertyGeneratedInfo | Metadata record for each property (Name, Type, HasSetter) |
| ReflectorJsonConverter | System.Text.Json converter using reflectors |
| Assembly Info Generation | Auto-generates static class with build constants |
Classes and records using the [Reflector] attribute must be declared as partial. Without partial, you'll get compiler error SHINYREFL001:
[Reflector]
public partial class MyClass // partial required!
{
public string Name { get; set; }
public int Age { get; set; }
}
This applies to records as well:
[Reflector]
public partial record MyRecord(string Name, int Age);
Install NuGet Package:
dotnet add package Shiny.Reflector
The NuGet package includes both the runtime library and the source generator. No additional package is needed.
When generating code using Shiny Reflector, follow these conventions:
Always mark classes as partial and apply [Reflector]:
using Shiny.Reflector;
[Reflector]
public partial class MyModel
{
public string Name { get; set; }
public int? Age { get; set; }
public DateTime CreatedAt { get; set; }
}
Access properties through the generated reflector:
var model = new MyModel { Name = "Hello", Age = 25 };
var reflector = model.GetReflector();
// Enumerate properties
foreach (var prop in reflector.Properties)
{
Console.WriteLine($"{prop.Name} ({prop.Type.Name}) HasSetter={prop.HasSetter}");
}
// Typed access
var name = reflector.GetValue<string>("Name");
// Indexer access (case-insensitive)
var age = reflector["age"];
// Set values
reflector.SetValue("Name", "Updated");
reflector["Age"] = 30;
For objects without [Reflector], use the fallback:
var reflector = someObject.GetReflector(fallbackToTrueReflection: true);
Use ReflectorJsonConverter for reflection-free JSON:
// Generic converter for a specific type
var options = new JsonSerializerOptions();
options.Converters.Add(new ReflectorJsonConverter<MyModel>());
// Or factory converter for all types
options.Converters.Add(new ReflectorJsonConverter());
var json = JsonSerializer.Serialize(model, options);
var deserialized = JsonSerializer.Deserialize<MyModel>(json, options);
Configure in the project file:
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ReflectorItem Include="MyCustomVar"
Value="Hello World"
Visible="false" />
</ItemGroup>
</Project>
This generates:
public static class AssemblyInfo
{
public const string Company = "MyCompany";
public const string Version = "1.0.0";
public const string TargetFramework = "net9.0";
public const string MyCustomVar = "Hello World";
}
Usage:
Console.WriteLine("Version: " + AssemblyInfo.Version);
Console.WriteLine("Custom: " + AssemblyInfo.MyCustomVar);
When using CommunityToolkit.Mvvm source generation with partial properties:
<PropertyGroup>
<LangVersion>preview</LangVersion>
</PropertyGroup>
[Reflector]
public partial class MyViewModel : ObservableObject
{
[ObservableProperty]
public partial string MyProperty { get; set; }
}
Models/ or domain-appropriate folders[Reflector] classes focused - one per file when possibleProperty enumeration:
var reflector = myObject.GetReflector();
foreach (var prop in reflector.Properties)
{
var value = reflector[prop.Name];
Console.WriteLine($"{prop.Name}: {value}");
}
Safe property access:
var reflector = myObject.GetReflector();
if (reflector.TryGetValue<string>("Name", out var name))
Console.WriteLine($"Name = {name}");
if (reflector.HasProperty("Email"))
reflector["Email"] = "[email protected]";
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]);
}
partial - Required for source generation; without it you get SHINYREFL001fallbackToTrueReflection when working with unattributed typesGetValue<T>() and SetValue<T>() over indexers for type safetyreflector["name"] and reflector["Name"] are equivalent[Reflector], but records must use partial keywordReflectorJsonConverter factory - Register new ReflectorJsonConverter() (non-generic) for broad coverage| Property | Default | Purpose |
|----------|---------|---------|
| ShinyReflectorUseInternalAccessors | false | Generate internal vs public accessors |
| ShinyReflectorGenerateAssemblyInfo | true | Enable/disable AssemblyInfo generation |
| ShinyReflectorAssemblyInfoClassName | AssemblyInfo | Class name for generated constants |
| ShinyReflectorAssemblyInfoNamespace | Root namespace | Namespace for generated AssemblyInfo |
For detailed templates and examples, see:
reference/templates.md - Code generation templates for reflector classesreference/api-reference.md - Full API surface, interfaces, and configurationdevops
Guide for implementing push notifications in .NET MAUI apps using Shiny.Push (native FCM/APNs) and Shiny.Push.AzureNotificationHubs
tools
Cross-platform local notification management for .NET MAUI apps using Shiny, supporting scheduled, repeating, and geofence-triggered notifications with channels, badges, and interactive actions.
tools
GPS tracking, geofence monitoring, and motion activity recognition for .NET MAUI, iOS, and Android using Shiny.Locations
data-ai
Background job scheduling and execution for .NET MAUI (iOS/Android native OS schedulers) and in-process jobs for plain .NET, Linux, macOS, and Blazor WASM using Shiny.Jobs