Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decorator support? #157

Open
Razenpok opened this issue Mar 10, 2021 · 8 comments
Open

Decorator support? #157

Razenpok opened this issue Mar 10, 2021 · 8 comments
Labels

Comments

@Razenpok
Copy link

Scrutor library adds a cool decorator feature for Microsoft.Extensions.DependencyInjection. Is it possible to provide a similar thing here?

https://github.com/khellang/Scrutor

builder.Register<IPictureRepository, PictureRepository>();
builder.Decorate<IPictureRepository, CachingPictureRepository>();
builder.Decorate<IPictureRepository, LoggingPictureRepository>();

// Resolve<IPictureRepository> would resolve LoggingPictureRepository with this hierarchy of decoration
// - LoggingPictureRepository
// | - CachingPictureRepository
//   | - PictureRepository
@hadashiA
Copy link
Owner

Ok, this may be useful.
I think the Decorater pattern needs some support on the DI library side.
( Because we need to resolve the same interface).

This may require a little work on the core functionality, so let me consider it.

However, I may prefer to make this like a plugin.

@lucasmontec
Copy link

I'm also interested in this! This is great to attach functionality to existing code without changing it. Keeping it SOLID.

@vu-truong
Copy link

Any update?

@hadashiA
Copy link
Owner

hadashiA commented May 1, 2022

In #372, I am trying to add an interface that will allow the ConotainerBuilder to be modified.
I believe this will allow for the implementation of perhaps the following:

        public void RegisterDecorator(Type interfaceType, Type decoratorType)
        {
            for (var i = 0; i < Count; i++)
            {
                var entry = this[i];
                var isTarget = entry.ImplementationType.IsInterface &&
                               entry.ImplementationType == interfaceType;

                if (entry.InterfaceTypes is { } interfaceTypes)
                {
                    foreach (var t in interfaceTypes)
                    {
                        if (t == interfaceType)
                        {
                            isTarget = true;
                            break;
                        }
                    }
                }

                if (isTarget)
                {
                    this[i] = new DecoratorRegistrationBuilder(this[i], decoratorType); 
                }
            }
        }
    public class DecoratorRegistrationBuilder : RegistrationBuilder
    {
        readonly RegistrationBuilder inner;
        readonly Type decorateType;
        
        public DecoratorRegistrationBuilder(RegistrationBuilder inner, Type decoratorType) 
            : base(decoratorType, inner.Lifetime)
        {
            this.inner = inner;
            decorateType = inner.InterfaceTypes != null ? inner.InterfaceTypes[0] : inner.ImplementationType;
            InterfaceTypes = inner.InterfaceTypes;
            As(decorateType);
        }
    
        public override Registration Build()
        {
            var injector = InjectorCache.GetOrBuild(ImplementationType);
            var innerRegistration = inner.Build();
            
            var provider = new FuncInstanceProvider(container =>
            {
                var innerInstance = container.Resolve(innerRegistration);
                var parameters = new IInjectParameter[Parameters == null ? 1 : Parameters.Count];
                Parameters?.CopyTo(parameters);
                parameters[parameters.Length - 1] = new TypedParameter(decorateType, innerInstance);
                return injector.CreateInstance(container, parameters);
            });
            return new Registration(ImplementationType, Lifetime, InterfaceTypes, provider);
        }
    }

There are several considerations for this 🤔

  • The implementation of this decorator will probably be caught by the circular dependency checker.
    • I have not yet decided if the Decorator should be made like a plugin.

@vu-truong
Copy link

any news on this?

@vu-truong
Copy link

Any update?

@dreamcodestudio
Copy link

dreamcodestudio commented Nov 28, 2023

... +

@hadashiA
Copy link
Owner

working in #625

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants