dadhi / DryIoc

DryIoc is fast, small, full-featured IoC Container for .NET
MIT License
1.01k stars 123 forks source link

Conditional registrations #631

Open dadhi opened 8 months ago

dadhi commented 8 months ago

Discussed in https://github.com/dadhi/DryIoc/discussions/630

Originally posted by **TheHunter** February 2, 2024 [ContainerTest.txt](https://github.com/dadhi/DryIoc/files/14139637/ContainerTest.txt) Hi everyone, I'm finding a problem using a conditional registrations, when I use at the end one registration without condition, the previous registrations (with condition) don't work in one specific case, when registrations with condition have a lower scope than the default registration (without condition), and it seems that the default one have the precedence, ignoring previous conditional registrations. Take a look to this example: ```csharp public class ServiceConsumerA(IService service) { public IService Service { get; private set; } = service; } public class ServiceConsumerB(IService service) { public IService Service { get; private set; } = service; } public class MyServiceA : IService { } public class MyServiceB : IService { } public interface IService { } ``` ```csharp [Fact] public void TestWithDefaultScopeToSingleton() { var container = new Container(); // it works even for Reuse.Singleton var scopeA = Reuse.Transient; var scopeB = Reuse.Singleton; container.Register(typeof(IService), typeof(MyServiceA), reuse: scopeA , setup: Setup.With(condition: request => request.DirectParent.ServiceType == typeof(ServiceConsumerA)) ); // the intention is having a default resolution if previous conditions aren't satisfied !! container.Register(typeof(IService), typeof(MyServiceB), reuse: scopeB ); container.Register(typeof(ServiceConsumerA)); container.Register(typeof(ServiceConsumerB)); var consumerA = container.Resolve(); var consumerB = container.Resolve(); Assert.NotNull(consumerA); Assert.NotNull(consumerB); // here is the mismatch from consumerA.Service type !!. Assert.Equal(typeof(MyServiceA), consumerA.Service.GetType()); Assert.Equal(typeof(MyServiceB), consumerB.Service.GetType()); } ``` If you try it only changing the scope of scopeA in Singleton it works. ```csharp [Fact] public void TestWithIdenticalScopes() { var container = new Container(); // it works even for Reuse.Singleton var scopeA = Reuse.Transient; var scopeB = Reuse.Transient; container.Register(typeof(IService), typeof(MyServiceA), reuse: scopeA , setup: Setup.With(condition: request => request.DirectParent.ServiceType == typeof(ServiceConsumerA)) ); // the intention is having a default resolution if previous conditions aren't satisfied !! container.Register(typeof(IService), typeof(MyServiceB), reuse: scopeB ); container.Register(typeof(ServiceConsumerA)); container.Register(typeof(ServiceConsumerB)); var consumerA = container.Resolve(); var consumerB = container.Resolve(); Assert.NotNull(consumerA); Assert.NotNull(consumerB); // those asserts work, so types match ! Assert.Equal(typeof(MyServiceA), consumerA.Service.GetType()); Assert.Equal(typeof(MyServiceB), consumerB.Service.GetType()); } ``` Probably something is wrong in the example, mainly in the registration of default registration (without condition). The complete unit test is attached in this post. Any help will be appreciated :). Thanks