Ответ 1
Как вы говорите, ваши два индивидуальных требования поддерживаются AutoFac.
- Временное разрешение параметров конструктора может быть реализовано с помощью Параметрированное создание объектов
- Разрешение конкретной реализации службы может быть реализовано с помощью Keyed Service Lookup
Однако, похоже, нет прямой поддержки для использования этих двух конструкций вместе. То есть следующий не работает:
public enum ServiceType
{
ServiceA,
ServiceB
}
public class MyComponent
{
public MyComponent(Func<string, IIndex<ServiceType, IService> factory)
{
var service = factory("some_string")[ServiceType.ServiceA];
}
}
Моя работа для этого всегда заключалась в переместить разрешение службы на factory для каждой реализации службы. Это работает следующим образом:
- Компоненты, зависящие от конкретной реализации службы, принимают делегат AutoFac factory, который разрешает factory, относящийся к требуемой реализации службы
- В свою очередь, сервисные заводы зависят от делегата AutoFac factory, который знает, как создать конкретную реализацию службы из параметров конструктора (runtime) службы
- Этот подход использует собственные конструкторы AutoFac и не имеет каких-либо зависимостей от AutoFac за пределами проводки контейнера.
Вот пример грубого и готового. Обратите внимание, что несколько фабрик могут быть сведены к одному родовому factory, но я оставил его как есть для ясности:
Реализации служб
public enum ServiceType
{
NotSet,
ServiceA,
ServiceB
}
public interface IService
{
string DoWork();
}
public class ServiceA : IService
{
private readonly string _name;
public ServiceA(string name)
{
_name = name;
}
public string DoWork()
{
throw new NotImplementedException();
}
}
public class ServiceB : IService
{
private readonly string _name;
public ServiceB(string name)
{
_name = name;
}
public string DoWork()
{
throw new NotImplementedException();
}
}
Сервисные заводы
public interface IServiceFactory
{
IService Create(string name);
}
public class ServiceAFactory : IServiceFactory
{
private readonly Func<string, ServiceA> _factory;
public ServiceAFactory(Func<string, ServiceA> factory)
{
_factory = factory;
}
public IService Create(string name)
{
return _factory(name);
}
}
public class ServiceBFactory : IServiceFactory
{
private readonly Func<string, ServiceB> _factory;
public ServiceBFactory(Func<string, ServiceB> factory)
{
_factory = factory;
}
public IService Create(string name)
{
return _factory(name);
}
}
Регистрация услуг
builder.RegisterType<ServiceA>().As<ServiceA>();
builder.RegisterType<ServiceB>().As<ServiceB>();
builder.RegisterType<ServiceAFactory>().Keyed<IServiceFactory>(ServiceType.ServiceA);
builder.RegisterType<ServiceBFactory>().Keyed<IServiceFactory>(ServiceType.ServiceB);
builder.RegisterType<ComponentWithServiceDependency>().As<ComponentWithServiceDependency>();
Использование примера
public class ComponentWithServiceDependency
{
private readonly IService _service;
public ComponentWithServiceDependency(IIndex<ServiceType, IServiceFactory> serviceFactories)
{
// Resolve the ServiceB service implementation,
// using the string "test" as its constructor dependency
_service = serviceFactories[ServiceType.ServiceB].Create("test");
}
public string Test()
{
return _service.DoWork();
}
}