Как передать аргумент во время выполнения?

Мы мигрируем из StructureMap в Lamar, но я не смог найти "версию Lamar" для передачи аргументов во время выполнения.

У нас есть класс, который требует строковый аргумент (псевдокод):

public class MyRepository {
  public MyRepository(string accountId) {}
}

... и завод

public class MyRepoFactory(Container container) {
  public MyRepository GetRepositoryForAccount(string accountId) => 
     container
        // With() is not available in Lamar?
        .With("accountId").EqualTo(accountId)
        .GetInstance<IMyRepository>();
}

На самом деле существуют дополнительные зависимости.

Как можно сказать, Ламар GetInstance() за IMyRepository и использовать значение xy для аргумента конструктора с именем accountId?

1 ответ

Я вижу два подхода с Ламаром.

Использование свойств

Пока Ламар не предлагает With()Обходной путь может заключаться в том, чтобы сделать учетную запись свойством, заданным вами в методе фабрики, или чтобы фабрика просто получала все зависимости хранилища вручную из контейнера. В конце концов, это фабрика, поэтому ее тесная связь с типом, который она производит, кажется хорошей с точки зрения дизайна.

Использование контекстов

Более хорошим подходом может быть установка accountId в контексте и использование контекста в хранилище:

public class ExecutionContext
{
    public Guid AccountId { get; set; } = Guid.NewGuid();
}

Репозиторий выглядит так

public class MyRepository
{
    public ExecutionContext Context { get; }

    public MyRepository(ExecutionContext context)
    {
        Context = context;
    }
}

Сделать контекст инъекционным...

var container = new Container(_ =>
{
    _.Injectable<ExecutionContext>();
});

а потом на вашем заводе...

public MyRepository GetRepositoryForAccount(string accountId) {
    var nested = container.GetNestedContainer();
    var context = new ExecutionContext{ AccountId = accountId };
    nested.Inject(context);
    return nested.GetInstance<IMyRepository>()
}

Документация: https://jasperfx.github.io/lamar/documentation/ioc/injecting-at-runtime/

Вы также можете подумать, действительно ли вам нужна фабрика в этом сценарии, если использование вложенного, инъецируемого контейнера напрямую может привести к более чистому дизайну.

Грубым, но простым решением может быть следующий код:

var type = container.Model.DefaultTypeFor(typeof(IMyRepository));
var constructor = type.GetConstructor(new[] { typeof(string) });
var instance = constructor.Invoke(new object[] { accountId });
return (IMyRepository)instance;
Другие вопросы по тегам