VContainer
VContainer copied to clipboard
Decorator support?
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
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.
I'm also interested in this! This is great to attach functionality to existing code without changing it. Keeping it SOLID.
Any update?
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.
any news on this?
Any update?
... +
working in #625