< Summary

Information
Class: NexusLabs.Needlr.Generators.OpenDecoratorForAttribute
Assembly: NexusLabs.Needlr.Generators.Attributes
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators.Attributes/OpenDecoratorForAttribute.cs
Line coverage
80%
Covered lines: 4
Uncovered lines: 1
Coverable lines: 5
Total lines: 101
Line coverage: 80%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_OpenGenericServiceType()100%210%
get_Order()100%11100%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators.Attributes/OpenDecoratorForAttribute.cs

#LineLine coverage
 1using System;
 2
 3namespace NexusLabs.Needlr.Generators;
 4
 5/// <summary>
 6/// Marks a generic class as a decorator for all closed implementations of an open generic interface.
 7/// This is a source-generation only feature - the generator discovers all closed implementations
 8/// at compile time and emits decorator registrations for each.
 9/// </summary>
 10/// <remarks>
 11/// <para>
 12/// Use this attribute when you want to apply a single decorator implementation to ALL
 13/// closed types of an open generic interface. For example, to add logging to every
 14/// <c>IHandler&lt;T&gt;</c> implementation.
 15/// </para>
 16/// <para>
 17/// The decorated class must:
 18/// <list type="bullet">
 19/// <item><description>Be an open generic class with matching type parameter arity</description></item>
 20/// <item><description>Implement the open generic interface specified</description></item>
 21/// <item><description>Accept the open generic interface as a constructor parameter (to wrap the inner service)</descrip
 22/// </list>
 23/// </para>
 24/// <para>
 25/// At compile time, the source generator:
 26/// <list type="number">
 27/// <item><description>Discovers all closed implementations of the open generic interface</description></item>
 28/// <item><description>Emits <c>AddDecorator&lt;TService, TDecorator&gt;</c> for each closed type</description></item>
 29/// </list>
 30/// </para>
 31/// </remarks>
 32/// <example>
 33/// <code>
 34/// public interface IHandler&lt;T&gt;
 35/// {
 36///     Task HandleAsync(T message);
 37/// }
 38///
 39/// // Concrete handlers
 40/// public class OrderHandler : IHandler&lt;Order&gt; { ... }
 41/// public class PaymentHandler : IHandler&lt;Payment&gt; { ... }
 42///
 43/// // Open generic decorator - applies to ALL IHandler&lt;T&gt; implementations
 44/// [OpenDecoratorFor(typeof(IHandler&lt;&gt;))]
 45/// public class LoggingDecorator&lt;T&gt; : IHandler&lt;T&gt;
 46/// {
 47///     private readonly IHandler&lt;T&gt; _inner;
 48///     private readonly ILogger&lt;LoggingDecorator&lt;T&gt;&gt; _logger;
 49///
 50///     public LoggingDecorator(IHandler&lt;T&gt; inner, ILogger&lt;LoggingDecorator&lt;T&gt;&gt; logger)
 51///     {
 52///         _inner = inner;
 53///         _logger = logger;
 54///     }
 55///
 56///     public async Task HandleAsync(T message)
 57///     {
 58///         _logger.LogInformation("Handling {Type}", typeof(T).Name);
 59///         await _inner.HandleAsync(message);
 60///         _logger.LogInformation("Handled {Type}", typeof(T).Name);
 61///     }
 62/// }
 63///
 64/// // Generator emits:
 65/// // services.AddDecorator&lt;IHandler&lt;Order&gt;, LoggingDecorator&lt;Order&gt;&gt;();
 66/// // services.AddDecorator&lt;IHandler&lt;Payment&gt;, LoggingDecorator&lt;Payment&gt;&gt;();
 67/// </code>
 68/// </example>
 69[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
 70public sealed class OpenDecoratorForAttribute : Attribute
 71{
 72    /// <summary>
 73    /// Initializes a new instance of the <see cref="OpenDecoratorForAttribute"/> class.
 74    /// </summary>
 75    /// <param name="openGenericServiceType">
 76    /// The open generic interface type to decorate (e.g., <c>typeof(IHandler&lt;&gt;)</c>).
 77    /// Must be an open generic interface.
 78    /// </param>
 82079    public OpenDecoratorForAttribute(Type openGenericServiceType)
 80    {
 82081        OpenGenericServiceType = openGenericServiceType;
 82082    }
 83
 84    /// <summary>
 85    /// Gets the open generic interface type that this decorator wraps.
 86    /// </summary>
 087    public Type OpenGenericServiceType { get; }
 88
 89    /// <summary>
 90    /// Gets or sets the order in which this decorator is applied relative to
 91    /// other decorators for the same service. Lower values are applied first
 92    /// (closer to the original implementation). Default is 0.
 93    /// </summary>
 94    /// <remarks>
 95    /// <para>
 96    /// When multiple decorators exist for the same open generic interface,
 97    /// they are applied in order from lowest to highest Order value.
 98    /// </para>
 99    /// </remarks>
 820100    public int Order { get; set; } = 0;
 101}