Skip to content

Conversation

Copilot
Copy link

@Copilot Copilot AI commented Aug 6, 2025

This PR addresses the performance and flexibility limitations in the decorator system by eliminating reflection-based proxy creation and adding support for decorating concrete classes (not just interfaces).

Problem

The existing decorator implementation had two major limitations:

  1. Reflection overhead: When decorating services registered with factory functions, the system created dynamic proxy types using System.Reflection.Emit, which added complexity and performance overhead.

  2. Interface-only restriction: The decorator system only supported interfaces, throwing an exception for concrete classes with the message "Service type X is not an interface."

Solution

🎯 Eliminated Reflection-Based Proxy Creation

Before: Factory-registered services required dynamic proxy type creation

// This triggered reflection-based proxy creation
services.AddTransient<IService>(_ => new ServiceImpl());
services.Decorate<IService, ServiceDecorator>();

After: Direct service creation without proxy types

// Same usage, but no reflection overhead
services.AddTransient<IService>(_ => new ServiceImpl());
services.Decorate<IService, ServiceDecorator>(); // No proxy creation!

🎯 Added Support for Class Decoration

Before: Only interfaces could be decorated

services.AddTransient<ConcreteService>(); 
services.Decorate<ConcreteService, ServiceDecorator>(); // ❌ InvalidOperationException

After: Both interfaces and classes supported

services.AddTransient<ConcreteService>();
services.Decorate<ConcreteService, ServiceDecorator>(); // ✅ Works perfectly

Implementation Details

The new decorator logic directly creates services using the original ServiceDescriptor information instead of relying on proxy types:

  • Type registrations: Creates instances using ActivatorUtilities.CreateInstance
  • Instance registrations: Uses the registered instance directly
  • Factory registrations: Invokes the original factory function directly
  • Keyed services: Maintains full support for all registration types

Benefits

  • Performance: Eliminated reflection overhead during decorator creation
  • Simplicity: Removed complex dynamic type generation code
  • Flexibility: Support for both interfaces and concrete classes
  • Compatibility: Zero breaking changes to existing API

Testing

Added comprehensive test coverage for class decoration scenarios:

  • Decorate_ConcreteClass_Registered_As_Type
  • Decorate_ConcreteClass_Registered_As_Instance
  • Decorate_ConcreteClass_Registered_As_Factory

All existing decorator tests continue to pass, ensuring backward compatibility.

Fixes #11.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI and others added 2 commits August 6, 2025 10:08
@Copilot Copilot AI changed the title [WIP] Decorator: Look for a way to avoid creating new interfaces with reflections when configuring decorators Remove reflection-based proxy creation and enable class decoration in service decorators Aug 6, 2025
@Copilot Copilot AI requested a review from AGiorgetti August 6, 2025 10:19
Copilot finished work on behalf of AGiorgetti August 6, 2025 10:19
Copy link
Contributor

@AGiorgetti AGiorgetti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Update the changelog adding this story and the changes made.

// Remove the original service descriptor that has the service type
services.Remove(originalServiceDescriptor);

// Create a new service descriptor for the decorator
Copy link
Contributor

@AGiorgetti AGiorgetti Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot improve the comment explaining the logic, exaplin why it shuould work

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improved comments throughout ServiceCollectionExtensions.Decorators.cs explaining why the implementation works - the new approach preserves original registration information and creates wrapper factories that eliminate reflection overhead while supporting both interfaces and concrete classes. Commit 7693b10

@AGiorgetti AGiorgetti self-requested a review August 6, 2025 13:12
@AGiorgetti AGiorgetti marked this pull request as ready for review August 6, 2025 13:13
@AGiorgetti
Copy link
Contributor

@copilot update the changelog, improve the comments in ServiceCollectionExtensions.Decorators.cs explaining why it should work.
@copilot execute test tests and verify everything pass

…ning logic and design rationale

Co-authored-by: AGiorgetti <[email protected]>
Copy link
Author

Copilot AI commented Aug 6, 2025

@copilot Update the changelog adding this story and the changes made.

Added comprehensive changelog entry documenting the decorator system enhancements, including elimination of reflection-based proxy creation and support for concrete class decoration. Commit 7693b10

@copilot update the changelog, improve the comments in ServiceCollectionExtensions.Decorators.cs explaining why it should work.
@copilot execute test tests and verify everything pass

Completed all requested changes: updated changelog, improved comments explaining the logic, and verified all tests pass. All 13 decorator tests pass including the new concrete class decoration tests. Commit 7693b10

Copilot finished work on behalf of AGiorgetti August 6, 2025 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decorator: Look for a way to avoid creating new interfaces with reflections when configuring decorators

2 participants