Autofa c: Разрешение от нескольких реализаций одного интерфейса и от разных производителей - PullRequest
0 голосов
/ 13 июля 2020

Возможно ли с Autofa c создавать экземпляры классов, реализующих один и тот же интерфейс, но имеющих разные конструкторы, и что он определяет, какой класс создавать?

public sealed class LoginModuleTypeItemViewModel : IInternalModuleTypeItemViewModel
{
    public LoginModuleTypeItemViewModel(LoginModuleTypeExtraModel model)
    {
    }
}

public sealed class TypeObjectModuleTypeItemViewModel : IInternalModuleTypeItemViewModel
{
    public TypeObjectModuleTypeItemViewModel(TypeObjectModuleTypeExtraModel model)
    {
    }
}

builder.RegisterType<TypeObjectModuleItemViewModel>().As<IInternalModuleItemViewModel>().SingleInstance();
builder.RegisterType<LoginModuleItemViewModel>().As<IInternalModuleItemViewModel>().SingleInstance();

_container.Resolve<IInternalModuleItemViewModel>(new TypedParameter(model.GetType(), model));

Ответы [ 2 ]

1 голос
/ 14 июля 2020

Когда вы регистрируете несколько компонентов («классов»), предоставляющих один и тот же интерфейс («службу»), он последний среди побед . Это означает, что если у вас есть:

var builder = new ContainerBuilder();
builder.RegisterType<First>().As<IThing>();
builder.RegisterType<Second>().As<IThing>();
builder.RegisterType<Third>().As<IThing>();
var container = builder.Build();

Тогда, когда вы попытаетесь разрешить IThing, всегда будет последним.

var thing = container.Resolve<IThing>();
Assert.IsType<Third>(thing); // this is true

Неважно, какие параметры вы передаете. Если вы разрешите один экземпляр вещи, он всегда будет последним в победах. Здесь нет «выбрать вещь на основе параметров, которые я передаю». И если подумать, это имеет смысл - с точки зрения внедрения / инверсии зависимостей потребитель никогда не должен знать или заботиться о том, какой тип реализует интерфейс .

Если вы расширяете logi c, о котором просите, что, если бы у вас было это?

public class First : IThing
{
  public First(Dependency dep) : { }
}

public class Second : IThing
{
  public Second(Dependency dep, OtherDependency other) : { }
}

А затем вы зарегистрировались ...

var builder = new ContainerBuilder();

// We can resolve OtherDependency from the container
builder.RegisterType<OtherDependency>();

// The two things we'd pick from
builder.RegisterType<First>().As<IThing>();
builder.RegisterType<Second>().As<IThing>();

var container = builder.Build();

// OtherDependency can come from the container
// but you're providing the Dependency as a parameter
var thing = container.Resolve<IThing>(new TypedParameter(typeof(Dependency), new Dependency());

В этом примере .. .. какой тип thing? Это First, потому что единственный параметр - Dependency? Или это Second из-за стандартного "последнего в победе" и потому, что OtherDependency может поступать из контейнера?

Если это First, то ... какой толк от контейнера для внедрения зависимостей вообще, поскольку вы фактически "новичок" в конкретном типе c на основе параметров конструктора, которые вам все равно нужно знать?

Если это Second, то ... вы не получаете то, о чем вы просите, где вы каким-то образом получаете «вещь, соответствующую параметрам конструктора».

Я понимаю, что приведенное выше не дает вам ответа , но я надеюсь, что он получит в место, где вы можете понять, почему, возможно, то, что вы просите, не является тем, что Autofa c (или любой другой контейнер DI) может предоставить - у вас небольшая проблема с дизайном.

Ваш вопрос касается в одном из Autofa c FAQs интересно, как «выбрать реализацию по контексту».

Я предполагаю, что где-то в этой строке у вас есть параметр (или что-то еще) и на основе этого вам нужно «выбрать» другой тип модели представления.

FAQ, на который я ссылался, объясняет, почему это проблема дизайна, и предлагает несколько способов ее решения. Я не буду здесь повторять все, но вкратце:

  1. Вы можете перепроектировать / изменить интерфейсы, чтобы они не были идентичными. Если они не могут быть обработаны как идентичные, они не идентичны, даже если кажется, что у них одинаковые методы.
  2. Вы можете обновить способ регистрации вещей, которые потребляют ваши различные вещи. поэтому они в некоторой степени жестко запрограммированы, чтобы принимать тот тип, который они ожидают. Это сложная вещь, включающая ResolvedParameters и лямбда-регистрации, и на этой странице часто задаваемых вопросов есть рабочий пример, объясняющий это.
  3. Вы можете использовать службы с ключами, чтобы присвоить каждому компоненту поставщика идентификатор, а затем использовать эти ключи / ID в атрибутах или во время операций ручного разрешения, чтобы указать то, что вы хотите.
  4. Вы можете использовать метаданные, чтобы прикрепить идентификатор поставщика или какой-либо другой идентификатор к регистрации каждого поставщика, чтобы «выбрать» нужный компонент резервного копирования во время выполнения .

Ознакомьтесь с FAQ для объяснений и примеров в коде. Здесь дается более глубокое объяснение того, как эти параметры будут работать.

0 голосов
/ 13 июля 2020

Да, работает нормально. Но не забудьте правильно разрешить с тем же типом, который у вас есть в конструкторе (если вы регистрируетесь с LoginModuleItemViewModel, модель должна иметь тип LoginModuleTypeExtraModel, если у вас нет допустимого конструктора с TypeObjectModuleTypeExtraModel в LoginModuleItemViewModel классе ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...