Предполагая, что вы не можете изменить способ, которым платформа вызывает локатор, и предполагая, что платформа использует Common Service Locator, используемый в качестве интерфейса между вашим контейнером и самим собой, вы можете добавить эту функциональность в пользовательскую реализацию IServiceLocator
:
// This adapter wraps the CSL LightCoreAdapter of LightCore itself.
public class LightCoreServiceLocatorAdapter : IServiceLocator
{
private readonly LightCoreAdapter container;
public LightCoreServiceLocatorAdapter(IContainer container)
{
// You need a reference to LightCore.CommonServiceLocator.dll.
this.container = new LightCoreAdapter(container);
}
public IEnumerable<TService> GetAllInstances<TService>()
{
return this.container.GetAllInstances<TService>();
}
public IEnumerable<object> GetAllInstances(Type serviceType)
{
return this.container.GetAllInstances(serviceType);
}
public TService GetInstance<TService>(string key)
{
if (key == null)
{
return this.container.GetInstance<TService>(null);
}
else
{
// This is custom logic
this.container.GetInstance<INamedFactory<TService>>().GetByKey(key);
}
}
public TService GetInstance<TService>()
{
return this.container.GetInstance<TService>();
}
public object GetInstance(Type serviceType, string key)
{
if (key == null)
{
return this.container.GetInstance(serviceType);
}
else
{
// This is custom logic
var facType = typeof(INamedFactory<>).MakeGenericType(serviceType);
var factory = (INamedFactory)this.container.GetInstance(facType);
return factory.GetByKey(key);
}
}
public object GetInstance(Type serviceType)
{
return this.container.GetInstance(serviceType);
}
object IServiceProvider.GetService(Type serviceType)
{
((IServiceProvider)this.container).GetService(serviceType);
}
}
Этот класс использует следующие два пользовательских интерфейса:
public interface INamedFactory
{
object GetByKey(string key);
}
public interface INamedFactory<T> : INamedFactory
{
T GetByKey(string key);
}
Используя этот пользовательский LightCoreServiceLocatorAdapter
и эти два пользовательских интерфейса, вы можете создавать собственные фабрики, такие как этот универсальный:
public sealed class NamedDelegateFactory<T> : INamedFactory<T>
{
private readonly Func<string, T> factory;
public NamedDelegateFactory(Func<string, T> factory)
{
this.factory = factory;
}
public T GetByKey(string key)
{
return this.factory(key);
}
object INamedFactory.GetByKey(string key)
{
return this.factory(key);
}
}
Который может быть зарегистрирован в контейнере следующим образом:
var factory = new NamedDelegateFactory<IMyType>(key =>
{
if (key == "Cool") return new MyType1();
else return new MyType2();
});
var builder = new ContainerBuilder();
builder.Register<INamedFactory<IMyType>>(c => factory);
Далее LightCoreServiceLocatorAdapter
можно создать следующим образом:
var adapter = new LightCoreServiceLocatorAdapter(builder.Build());
Microsoft.Practices.ServiceLocation.ServiceLocator
.SetLocatorProvider(() => adapter);
Вы можете зарегистрировать все именованные экземпляры с помощью интерфейса INamedFactory<T>
и использовать NamedDelegateFactory<T>
, обернутый делегатом, или реализовать пользовательский тип, который реализует INamedFactory<T>
.