Боюсь, Autofac не такой гибкий. Он поддерживает XML-конфигурацию , но я ожидаю, что он будет поддерживать только примитивные типы в качестве параметров конструктора.
С другой стороны, ваш пример, кажется, неверно использует внедрение зависимостей. DI в основном должен использоваться, когда ни компоненту инъекции не важно, кто его использует, ни потребителю компонента не важно, какую реализацию сервиса он получает. Я бы добавил свойство идентификации к ILogger
и IStorage
, чтобы MyService
получал все доступные регистраторы и хранилища, а внутри него реализовывал логику, которая обрабатывает свою конкретную конфигурацию, чтобы определить, какие комбинации использовать. Примерно так:
public interface ILogger
{
string Id { get; }
}
public class FileLogger : ILogger
{
public string Id { get { return "Logger.File"; } }
}
// etc.
public interface IStorage
{
string Id { get; }
}
public class RegistrySrorage : IStorage
{
public string Id { get { return "Storage.Registry"; } }
}
public class MyService
{
IList<Config> _EnabledConfigs;
public MyService(IEnumerable<ILogger> loggers, IEnumerable<IStorage> storages)
{
_EnabledConfigs = ParseXmlConfigAndCreateRequiredCombinations(loggers, storages);
}
class Config
{
public ILogger Logger { get; set; }
public IStorage Storage { get; set; }
}
}
// container config:
public static void ConfigureContainer(IContainerBuilder builder)
{
builder.RegisterType<FileLogger>.AsImplementedInterfaces();
// other loggers next...
builder.RegisterType<RegisterStorage>.AsImplementedInterfaces();
// then other storages
builder.RegisterType<MyService>();
}
И конфиг выглядит так:
<MyServiceConfig>
<EnabledCombinations>
<Combination Logger="Logger.File" Storage="Storage.Registry"/>
<!-- Add other enabled combinations -->
</EnabledCombinations>
</MyServiceConfig>
Подумай об этом. Бьюсь об заклад, это будет намного проще.
В качестве опции вы можете создать отдельный класс, отвечающий за настройку MyService
, чтобы MyService
не содержал логику, связанную с конфигурацией.
UPDATE
Если вам действительно нужна такая сложная логика для конфигураций зависимостей, которая лучше всего выражается в коде c #, лучше всего использовать Модули . Просто извлеките код, который настраивает то, что вам нужно, в отдельный модуль Autofac:
public class MyServiceConfigModule : Module
{
protected override void Load(ContainerBuilder builder)
{
// register some compopnent that uses MyService and initialize it with
// the required set of loggers and storages
builder.Register(ctx => new MyServiceConsumer(
new List<MyService>()
{
new MyService(new FileLogger(), new RegistrySrorage()),
new MyService(new FileLogger(), new DatabaseStorage()),
new MyService(new ConsoleLogger(), new FileStorage()),
new MyService(new DebugLogger(), new FileStorage()),
// same implementations as in previous instance are used but with different
// constructor parameter: for example, different destination in FileStorage
new MyService(new DebugLogger(), new FileStorage()),
}));
}
}
, поместите его в отдельную сборку «MyServiceConfig» и добавьте пару строк конфигурации в app.config
:
<autofac>
<modules>
<module type="MyServiceConfigModule, MyServiceConfig" />
</modules>
</autofac>
Когда вам нужно изменить его, вы можете написать новый исходный файл модуля, скомпилировать его на месте (csc.exe всегда присутствует на компьютере с .NET) и заменить его старым. Конечно, этот подход подходит только для конфигурации «время запуска».