Как разрешить зависимость с помощью именованного типа регистра в Unity?

public interface IFoo {}

public interface IBar {}

public class Foo1 :  IFoo {}

public class FooOne : IFoo {}
public class FooTwo : IFoo {}

public class BarOne : IBar
{
    public BarOne(IFoo foo) {}        
} 

public class BarTwo : IBar
{
    public BarTwo(IFoo foo) {}        
} 

 class Program
{
    static void Main(string[] args)
    {
        UnityContainer container = new UnityContainer();
        container.RegisterType<IFoo, FooOne>("One")
            .RegisterType<IFoo, FooTwo>("Two")
            .RegisterType<IBar, BarOne>("One")
            .RegisterType<IFoo, BarTwo>("Two");                

        string fooType = "One";
        string barType = "Two";

        IFoo myFoo = container.Resolve<IFoo>(fooType);
        IBar myBar = container.Resolve<IBar>(barType);
    }
}

Пример кода выше выдает эту ошибку:

Ошибка разрешения зависимости, type = "ConsoleApplication5.IBar", name = "Two". Исключение произошло во время: при разрешении. Исключение: InvalidOperationException — текущий тип ConsoleApplication5.IFoo является интерфейсом и не может быть создан. Вам не хватает сопоставления типов? ----------------------------------------------- В это время исключения, контейнер был:

Разрешение ConsoleApplication5.BarTwo,Two (сопоставлено с ConsoleApplication5.IBar, Two) Разрешение параметра "foo" конструктора ConsoleApplication5.BarTwo(ConsoleApplication5.IFoo foo) Разрешение ConsoleApplication5.IFoo,(none)

В моем решении используется DependencyResolver, который изменяет эту строку:

IBar myBar = container.Resolve<IBar>(barType);

к этому:

IBar myBar = container.Resolve<IBar>(barType, new DependencyOverride<IFoo>(myFoo));

Я хочу решить эту проблему, используя метод RegisterType. Возможно ли это или есть другое решение?

Спасибо.


person Mehmet Kemal Bayer    schedule 28.12.2016    source источник
comment
Некоторые детали отсутствуют. Вам нужно зарегистрировать IMessageType с контейнером где-то в вашем коде.   -  person Tilak    schedule 28.12.2016
comment
@Tilak Я редактирую пост. Сообщение об ошибке принадлежало исходному коду. Теперь вы можете увидеть сообщение об ошибке упрощенной версии.   -  person Mehmet Kemal Bayer    schedule 29.12.2016


Ответы (1)


Вы должны определить, какую из ваших регистраций IFoo named следует использовать при разрешении IBar.

container.RegisterType<IFoo, FooOne>("One")
         .RegisterType<IFoo, FooTwo>("Two")
         .RegisterType<IBar, BarOne>("One", new InjectionConstructor(
                                     new ResolvedParameter<IFoo>("One")))
         .RegisterType<IBar, BarTwo>("Two", new InjectionConstructor(
                                     new ResolvedParameter<IFoo>("Two")));

Проблема в том, что IFoo дважды регистрируется разными реализациями, и Unity не знает, какую из них следует использовать при разрешении этого типа.

person Mark    schedule 29.12.2016
comment
Вы правы, но в этом примере он предварительно разрешает IFoo с именованной регистрацией One. Я хочу, чтобы Unity продолжала использовать ту же регистрацию всякий раз, когда впоследствии ей нужно разрешить IFoo. Разве это не возможно или я упускаю какой-то момент? - person Mehmet Kemal Bayer; 29.12.2016
comment
IFoo One разрешается, потому что он не имеет зависимости в конструкторе. поэтому у Unity нет проблем с ее решением. Проблема заключалась в ваших регистрациях в IBar. Я не понимаю, что вы имеете в виду под одной и той же регистрацией. В вашем примере, когда вы разрешаете IFoo по имени, проблем нет, но IBar регистрируется дважды и имеет зависимость от IFoo, который также регистрируется дважды. Вы должны указать Unity при регистрации, какой из зарегистрированных IFoo он должен использовать. - person Mark; 29.12.2016
comment
@Mehmet Kemal Bayer, если вы хотите разрешить всегда одно и то же IFoo, зачем вам нужна именная регистрация? - person Johnny; 29.12.2016
comment
@Lepijohnny, потому что есть 4 возможности FooOne-BarOne, FooOne-BarTwo, FooTwo-BarOne, FooTwo-BarTwo, и решение о том, какая пара будет использоваться, зависит от внешних данных. - person Mehmet Kemal Bayer; 29.12.2016
comment
@Mehmet Kemal Bayer, и эти внешние данные можно изменить во время выполнения? - person Johnny; 29.12.2016
comment
@Mehmet Kemal Bayer, в этом случае я бы предпочел создать какую-то фабрику, которая будет разрешать эти интерфейсы в зависимости от входных данных, вместо того, чтобы пытаться решить это в Ioc. Затем зарегистрируйте этот IFactoryFooBar в Ioc. - person Johnny; 29.12.2016
comment
@Mehmet, как упомянул Лепижони, вам нужна Factory, потому что ваш IFoo (в IBar) зависит от данных. Если IFoo фиксирован (например, FooOne для Bar1 и FooTwo для BarTwo, то только вы можете использовать RegisterType. Или вы можете иметь BarOne, BarTwo, BarThree, BarFour для всех ваших сценариев и выбирать в зависимости от необходимости. - person Tilak; 29.12.2016
comment
@Lepijohnny, вот где мы были. Мы пытаемся использовать именованную регистрацию вместо фабрики, но я понимаю, что в нашем случае это невозможно. Спасибо вам всем. - person Mehmet Kemal Bayer; 30.12.2016