VContainer icon indicating copy to clipboard operation
VContainer copied to clipboard

Decorator support?

Open Razenpok opened this issue 4 years ago • 11 comments

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

Razenpok avatar Mar 10 '21 12:03 Razenpok

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.

hadashiA avatar Mar 24 '21 02:03 hadashiA

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

lucasmontec avatar Jan 20 '22 16:01 lucasmontec

Any update?

vu-truong avatar Apr 22 '22 12:04 vu-truong

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.

hadashiA avatar May 01 '22 06:05 hadashiA

any news on this?

vu-truong avatar Dec 18 '22 03:12 vu-truong

Any update?

vu-truong avatar Aug 22 '23 11:08 vu-truong

... +

yapetrichka avatar Nov 28 '23 14:11 yapetrichka

working in #625

hadashiA avatar Feb 11 '24 01:02 hadashiA