Injecting a specific instance of an interface usin

2019-05-11 15:27发布

问题:

I have a controller and it receives a specific instance of an interface.

The interface looks something like this:

public interface IMyInterface
{
   ... implementation goes here
}

And then I have some classes that implement this interface like this:

public class MyClassA : IMyInterface
{
   ... implementation goes here
}

public class MyClassB : IMyInterface
{
   ... implementation goes here
}

In my ControllerA I have the following constructor:

private ICustomerService customerService;
private IMyInterface myInterface;

puvlic ControllerA(ICustomerService customerService, IMyInterface myInterface)
{
   this.customerService = customerService;
   this.myInterface = myInterface;
}

In my global.ascx:

protected void Application_Start()
{
   // Autofac
   var builder = new ContainerBuilder();
   builder.RegisterControllers(Assembly.GetExecutingAssembly());
   builder.RegisterType<NewsService>().As<INewsService>();

   IContainer container = builder.Build();
   DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}

I specified that Autofac must supply the instance of ICustomerService. How would I specify the instance type for IMyInterface? In this case for ControllerA I would like Autofac to inject a ClassA instance. And for ControllerB I would like it to inject ClassB. How would I do this?

UPDATED 2011-02-14:

Let me give you my real life situation. I have a NewsController whose constructor looks like this:

public NewsController(INewsService newsService, IMapper newsMapper)
{
   Check.Argument.IsNotNull(newsService, "newsService");
   Check.Argument.IsNotNull(newsMapper, "newsMapper");

   this.newsService = newsService;
   this.newsMapper = newsMapper;
}

IMapper interface:

public interface IMapper
{
   object Map(object source, Type sourceType, Type destinationType);
}

I'm using AutoMapper. So my NewsMapper will look like this:

public class NewsMapper : IMapper
{
   static NewsMapper()
   {
      Mapper.CreateMap<News, NewsEditViewData>();
      Mapper.CreateMap<NewsEditViewData, News>();
   }

   public object Map(object source, Type sourceType, Type destinationType)
   {
      return Mapper.Map(source, sourceType, destinationType);
   }
}

So how would you recommend me do this now?

回答1:

IIRC:

builder.RegisterType<MyClassB>().As<IMyInterface>()

Update

Ok. Misread your question.

Actually, you should never ever do what you are asking. It's bound to give you problems. Why? Since there is no way to determine that the controllers can not work with the same interface. Amongst others, you are breaking the Liskovs Substitution Principle. It might not be a problem for you now, but let your application grow and come back in a year and try to understand why it isn't working.

Instead, create two new interfaces which derive from `IMyInterface´ and request those in the controllers.

Update 2

Qouting snowbear:

I disagree. OP doesn't says that his controller cannot work with instance of another type, he says that he wants to inject instances of different types. Let's imagine he has some service to extract data and he has a service which wraps this data service and provides caching functionality. I believe they should have the same interface in such situation and it is matter of DI to inject correct service

OP says just that: Controller A cannot work same class as controller B. Why would he else want to get different classes in different controllers for the same interface?

Brendan:

I personally would create a INewsMapper interface to make everything clear and sound. But if you do not want to do that: Go for a generic interface with the aggregate root as type parameter.

public interface IMapper<T> : IMapper where T : class
{

}

public class NewsMapper : IMapper<News>
{
   static NewsMapper()
   {
      Mapper.CreateMap<News, NewsEditViewData>();
      Mapper.CreateMap<NewsEditViewData, News>();
   }

   public object Map(object source, Type sourceType, Type destinationType)
   {
      return Mapper.Map(source, sourceType, destinationType);
   }
}

public NewsController(INewsService newsService, IMapper<News> newsMapper)
{
}