简体   繁体   中英

C# Dependency Injection - injecting interface that takes the same interface as a parameter

I've run into a bit of trouble trying to use dependency injection and need help.

I have a service IService that is implemented a few different ways in my application.

ServiceA : IService { public ServiceA(IDependencyA A, IDependency B) {...} }
ServiceB : IService { public ServiceB(IDependencyA A, IDependency B) {...} }
ServiceC : IService { public ServiceC(IService serviceA, IService serviceB) {...} }

In my startup.cs file, I will pick which one to use based on a parameter in my configuration file. Something like this:

var service = Configuration["AppConfig:Service:ID"];
switch(service) {
    case "A":
        services.AddTransient<IService, ServiceA>();
    case "B":
        services.AddTransient<IService, ServiceB>();
    case "C":
        // ??
}

I am able to create and use service A and service B very easily. I inject their dependencies A and B before hand and they get created just fine. The problem is with the third service. I need to inject the two other services into it. My question is: what is the best to do this?

Is there a way I can create concrete implementations of service A and B but somehow use the injected dependency A and B in their constructor? Do I have to mess around with the interfaces to get this to work? Maybe I have to change the constructor of ServiceC to take in concrete implementations of A & B?

Updated: don't know if it's the best solution, but I ended up doing the following to get it to work.

...
case "C":
    services.AddTransient<ServiceA>();
    services.AddTransient<ServiceB>();
    services.AddTransient<IService>(s => 
        new ServiceC(
            s.GetService<ServiceA>(),
            s.GetService<ServiceB>()
    ));

Another alternative. Introduce another interface, so you can register the both ServiceC and it's dependencies at the same time, without any ambiguity or circular references.

interface IService {}
interface IServiceImpl : IService {}

ServiceA : IServiceImpl { public ServiceA(IDependencyA A, IDependency B) {...} }
ServiceB : IServiceImpl { public ServiceB(IDependencyA A, IDependency B) {...} }
ServiceC : IService { public ServiceC(IEnumerable<IServiceImpl> services) {...} }

services.AddTransient<IServiceImpl, ServiceA>();
services.AddTransient<IServiceImpl, ServiceB>();
services.AddTransient<IService, ServiceC>();

There must be a better explanation for having such dependencies.

Microsoft.Extensions.DependencyInjection does not provide named registrations like other IoC containers ie Castle.Windsor.

There is a way you can still register ServiceC with instances of A and B

            services.AddTransient<ServiceA>();
            services.AddTransient<ServiceB>();
            services.AddTransient<IService>(serviceProvider => {
                return new ServiceC((IService)serviceProvider.GetRequiredService(typeof(ServiceA)), (IService)serviceProvider.GetRequiredService(typeof(ServiceB)));
            });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM