Autofac разрешение с другим разрешением для внутренней зависимости - PullRequest
0 голосов
/ 07 мая 2019

Предположим, следующие классы

class Foo : IFoo {
    Foo(IBar bar) {}
}

class Bar : IBar {
    Bar(IBaz baz)       
}

Мой контейнер настроен так, что вы можете различать IBaz по ключу.

builder.RegisterType<Baz1>().Keyed<IBaz>("1");    
builder.RegisterType<Baz2>().Keyed<IBaz>("2");

Теперь я хотел бы создать два класса, которым вводят IFoo, но дальше их нужно вводить либо Baz1, либо Baz2.

class MyClassA {
    MyClassA(IFoo foo) {
        var baz = foo.GetBar().GetBaz();
        //baz should be of type Baz1 
    }
}

class MyClassB {
    MyClassB(IFoo foo) {
       var baz = foo.GetBar().GetBaz();
       //baz should be of type Baz2
    }  
}

Как мне настроить / настроить что-то подобное? Предпочтительно с атрибутом в MyClassA и MyClassB.

Ответы [ 2 ]

2 голосов
/ 08 мая 2019

Ваш вопрос как бы колеблется между двумя нашими часто задаваемыми вопросами Autofac:

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

Мы объясняем, почему это проблема проектирования в разделе «Передача параметра» FAQ .Он говорит «параметр», но вы можете прочитать то же самое, что и «разрешение конкретной реализации интерфейса».Я обновлю / подправлю текст, чтобы он применялся здесь:

С технической точки зрения, вы решаете IFoo - компонент, который не должен знать о реализации IBaz.Реализация IFoo может измениться, или даже реализация IBar.Вы можете зарегистрировать заглушку для тестирования или переключиться на то, как все работает, так что привязка реализации не требуется.

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

Это также в основном примечание к «реализация по контексту»FAQ .В этом ответе есть целая аналогия, использующая объектно-ориентированную иерархию «животных», чтобы конкретным образом показать, почему это нехорошо.Я не буду повторно вставлять это здесь.Однако я еще раз повторю, что обработка этих двух реализаций IBaz по-разному нарушает принцип подстановки Лискова - то, что вы должны иметь возможность менять реализации IBaz, не ломая вещи.«Знание» о том, что один существенно отличается от другого, естественно подразумевает, что они не одинаковы и, следовательно, не должны реализовывать один и тот же интерфейс.(Может быть, обычный base интерфейс, но когда они используются, используемый интерфейс не будет прежним, если базовая реализация не может быть обработана одинаково.)

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

Опять же, извините, это, вероятно, не тот ответ, который вы хотите , но я думаю, что это ответ .

0 голосов
/ 08 мая 2019

Ну, это бы сработало.

        builder.RegisterType<MyClass1>()
            .WithParameter(
                (pi, ctx) => pi.Name == "foo",
                (pfoo, cfoo) => cfoo.Resolve<IFoo>(new ResolvedParameter(
                    (pbar, cbar) => pbar.Name == "bar",
                    (pbar, cbar) => cbar.Resolve<IBar>(new ResolvedParameter(
                        (pbaz, cbaz) => pbaz.Name == "baz",
                        (pbaz, cbaz) => cbaz.ResolveKeyed<IBaz>("1"))))))
            .AsSelf();

        builder.RegisterType<MyClass2>()
            .WithParameter(
                (pi, ctx) => pi.Name == "foo",
                (pfoo, cfoo) => cfoo.Resolve<IFoo>(new ResolvedParameter(
                    (pbar, cbar) => pbar.Name == "bar",
                    (pbar, cbar) => cbar.Resolve<IBar>(new ResolvedParameter(
                        (pbaz, cbaz) => pbaz.Name == "baz",
                        (pbaz, cbaz) => cbaz.ResolveKeyed<IBaz>("2"))))))
            .AsSelf();

Однако я не уверен, что это предпочтительный способ делать подобные вещи.

...