hadashiA / VContainer

The extra fast, minimum code size, GC-free DI (Dependency Injection) library running on Unity Game Engine.
https://vcontainer.hadashikick.jp
MIT License
1.88k stars 163 forks source link

Decorator support? #157

Open Razenpok opened 3 years ago

Razenpok commented 3 years ago

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 commented 3 years ago

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 commented 2 years ago

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

vu-truong commented 2 years ago

Any update?

hadashiA commented 2 years ago

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 🤔

vu-truong commented 1 year ago

any news on this?

vu-truong commented 1 year ago

Any update?

dreamcodestudio commented 9 months ago

... +

hadashiA commented 6 months ago

working in #625

hesselmonk commented 1 month ago

Any reason why this isn't merged yet?