S>А фабрика-то откуда взялась? Ее же тоже надо resolve'вить. К тому же, мы можем настроить контейнер при создании(resolve)типа использовать фабрику. Т.е. от ссылки на контейнер с последующим resolve мы не ушли.
Она разресолвится автоматом, я же в примере ее зарегистрировал там где региструется все, Foo будет где-то в иерархии и он разресолвится автоматом.
Например самая простая иерархия
public class RootClass
{
public RootClass( Foo foo )
{
...
}
}
после создания контейнера вызывается ресолв рута.
Контейнер упоминается только в одном месте в методе CreateContainer и более он не требуется
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[5]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, okon, Вы писали:
O>Вот так не хотелось бы делать, т.к. жестко задается имплементация Foo, Bar и сложно для подмены для тех же тестов.
Так и не надо. Фабрика знает конкретные типы (тип) и создает только какую-то свою группу объектов (или один объект). Все они связаны целью, логически и т.д.
Все что надо для создания этой группы — зависимости уже фабрики. И знать эти типы фабрика не должна. Т.е.
public class MyFabric : IMyFabric
{
public MyFabric (IFoo foo, IBar bar) { … }
public ISomething CreateSomething (int i)
{
return new Something (i, foo, bar);
// или например
// return new Something (foo(i), bar);
}
}
PS: Кстати, service locator IMHO не всегда антипаттерн. В некоторых случаях он вполне применим. Но, наверное, это тема для отдельного разговора.
Re[3]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, okon, Вы писали:
O>Возможно, но пока не понятно как внутри будет выглядеть Factory.CreateSomething, ведь в ней придется либо создавать инстансы вручную, либо как-то ресолвить зависимости.
Не нужно городить огород с фабриками-обёртками над контейнером. Фабрика должна просто создавать экземпляры конкретных классов, передавая им все долгоживущие зависимости через себя. Смысл такой фабрики в том, что она создаётся сразу, держит в себе нужные зависимости, и по запросу создаёт короткоживущие объекты, которым нужны эти зависимости.
Re: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, okon, Вы писали:
O>Пишут что передавать ссылку на IContainer плохо
Под плохо здесь имелось ввиду случай когда класс получает контейнер и сам тянет из него свои зависимости, а не получает их через аргументы конструктора. Если у нас какой-то класс постоянно создаёт какие-то объекты, что часто и бывает, то он зависит от фабрики этих объектов, вот пусть контейнер фабрику ему и передает в качестве зависимости.
P.S. В качестве фабрики, часто передаётся другой экземпляр контейнера "заряженного" под этот класс. Так у нас и все зависимости прописаны в одном месте и класс не сможет насоздавать ни чего лишнего.
Здравствуйте, okon, Вы писали:
O>Как такие сценарии правильно строятся без передачи и хранения ссылок на контейнеры ?
Задача состоит в создании экземпляра класса так ведь? А подобную задачу решат шаблон Factory.
public class A
{
private IMyFactory _myFactory;
public A (IMyFactory myFactory)
{
_myFactory = myFactory;
}
public IEnumerable<IMyClass> CalculateSomething()
{
return Enumerable.Range(1,100).Select( i => _myFactory.CreateSomething(i));
}
}
Re[6]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте, okon, Вы писали:
O>>Подразумевается что Resolve делается один раз для корневого объекта, а остальные зависимости сидят в конструкторах и вычисляются автоматом.
S>А почему я не могу для разных объектов,т.е. типов, делать Resolve? Для типа по контейнеру?
Основная идея я так понимаю делать это все при настройке контейнера, в том числе если что-то надо ресолвить когда-то потом, создается функция как-то так
и потом где-то в коде вместо того чтобы делать container.Resolve()
public class Foo
{
Foo( Func<MyClass> myClassFactory )
{
MyClass instance = myClassFactory();
}
}
вместо Func<MyClass>() можно делать какие-нибудь IMyClassFactory
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
как ресолвить не передавая ссылки на контейнер ( DI )
Пишут что передавать ссылку на IContainer плохо,
а как быть если нужно в процессе вычислений создать экземпляр класса и проинициализировать его поля, например с передачей контейнера, например
class A
{
IContainer container;
A( IContainer container )
{
this.container = container;
}
IEnumerable<B> CalculateSomething()
{
return Enumerable.Range(1,100).Select( i => container.Resolve<B>(new TypedParameter(type(int), i));
}
}
Как такие сценарии правильно строятся без передачи и хранения ссылок на контейнеры ?
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[2]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, Doc, Вы писали:
Doc>Здравствуйте, okon, Вы писали:
O>>Как такие сценарии правильно строятся без передачи и хранения ссылок на контейнеры ?
Doc>Задача состоит в создании экземпляра класса так ведь? А подобную задачу решат шаблон Factory. Doc>
Doc>public class A
Doc>{
Doc> private IMyFactory _myFactory;
Doc> public A (IMyFactory myFactory)
Doc> {
Doc> _myFactory = myFactory;
Doc> }
Doc> public IEnumerable<IMyClass> CalculateSomething()
Doc> {
Doc> return Enumerable.Range(1,100).Select( i => _myFactory.CreateSomething(i));
Doc> }
Doc>}
Doc>
Возможно, но пока не понятно как внутри будет выглядеть Factory.CreateSomething, ведь в ней придется либо создавать инстансы вручную, либо как-то ресолвить зависимости.
public class MyFactory : IMyFactory
{
IContainer container;
public MyFactory(IContainer container)
{
this.container = container;
}
IMyClass CreateSomething(int i)
{
return container.Resolve<IMyClass>(new TypedParameter(type(int), i);
}
}
т.е. пока не ясно как избавиться от container, т.к. конструктор типа имплементирующего IMyClass может принимать массу аргументов которые хотелось бы брать из контейнера а не передавать явно.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, okon, Вы писали:
O>Возможно, но пока не понятно как внутри будет выглядеть Factory.CreateSomething, ведь в ней придется либо создавать инстансы вручную, либо как-то ресолвить зависимости.
Фабрика создает вполне конкретные инстансы вполне конкретных (но только ей известных) типов.
Если надо создавать другие типы — создается другая фабрика.
Если посмотрите внимательно, то реализация Factory уже абстракция и прокинута в класс как интерфейс.
Метод CreateSomething должен возвращать интерфейс ISomething
Собственно больше абстракций / интерфейсов не требуется.
Re[3]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, okon, Вы писали:
O>Возможно, но пока не понятно как внутри будет выглядеть Factory.CreateSomething, ведь в ней придется либо создавать инстансы вручную, либо как-то ресолвить зависимости.
class A
{
Func<int, B> bFactory;
A(Func<int, B> bFactory)
{
this.bFactory = bFactory;
}
IEnumerable<B> CalculateSomething()
{
return Enumerable.Range(1, 100).Select(i => bFactory(i));
}
}
//////////////////////////////////var b = new A(i => container.Resolve<B>(new TypedParameter(typeof(int), i)))
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Re[4]: как ресолвить не передавая ссылки на контейнер ( DI )
_R_> //////////////////////////////////
_R_> var b = new A(i => container.Resolve<B>(new TypedParameter(typeof(int), i)))
_R_>
Но ссылку на контейнер так и не понятно где брать, она существует только при ресолве корня и далее ее передавать не рекомендуют.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[4]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, Doc, Вы писали:
Doc>Здравствуйте, okon, Вы писали:
O>>Возможно, но пока не понятно как внутри будет выглядеть Factory.CreateSomething, ведь в ней придется либо создавать инстансы вручную, либо как-то ресолвить зависимости.
Doc>Фабрика создает вполне конкретные инстансы вполне конкретных (но только ей известных) типов. Doc>Если надо создавать другие типы — создается другая фабрика.
Doc>Если посмотрите внимательно, то реализация Factory уже абстракция и прокинута в класс как интерфейс. Doc>Метод CreateSomething должен возвращать интерфейс ISomething Doc>Собственно больше абстракций / интерфейсов не требуется.
Имеется ввиду что B может принимать много аргументов конструктора, например
B( int I, IFoo foo, IBar bar )
{
}
В свою очередь Foo : IFoo тоже может иметь сложный конструктор с множеством параметров, через Resolve мы их вычисляем автоматом.
В контейнере мы регистрируем IFoo, IBar а в фабрике как предлагается инстанцировать их ?
Factory
{
B CreateB( int I )
{
return new B(i, new Foo( new X(), new Y() ), new Bar( new Z(), new X() );
}
}
Вот так не хотелось бы делать, т.к. жестко задается имплементация Foo, Bar и сложно для подмены для тех же тестов.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[6]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте, okon, Вы писали:
O>>Пишут что передавать ссылку на IContainer плохо,
S>Кто пишет?Чем плохо?
Кто уже не помню, но смысл был такой что весь граф зависимостей должен определяться в одном месте, а не быть размазан по коду.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[3]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, okon, Вы писали:
O>Кто уже не помню, но смысл был такой что весь граф зависимостей должен определяться в одном месте, а не быть размазан по коду.
Это логично, но ссылку на контейнер надо же передавать, иначе как объекты будут создаваться?
Кодом людям нужно помогать!
Re: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, okon, Вы писали:
O>Пишут что передавать ссылку на IContainer плохо, O>а как быть если нужно в процессе вычислений создать экземпляр класса и проинициализировать его поля, например с передачей контейнера, например O>Как такие сценарии правильно строятся без передачи и хранения ссылок на контейнеры ?
В Спринге это делается как то так
@Bean
public FactoryType factoryType(Dependency1 dep1, Dependency2 dep2) {
return new FactoryType(dep1, dep2);
}
Тут по сути фабрика которая создает объект типа FactoryType с зависимостями dep1, dep2.
ЗЫЖ Этот метод явно никто не вызывает, он вызывается контейнером и передает туда необходимые зависимости.
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте, okon, Вы писали:
O>>Кто уже не помню, но смысл был такой что весь граф зависимостей должен определяться в одном месте, а не быть размазан по коду.
S>Это логично, но ссылку на контейнер надо же передавать, иначе как объекты будут создаваться?
Подразумевается что Resolve делается один раз для корневого объекта, а остальные зависимости сидят в конструкторах и вычисляются автоматом.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[5]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, okon, Вы писали:
O>Подразумевается что Resolve делается один раз для корневого объекта, а остальные зависимости сидят в конструкторах и вычисляются автоматом.
А почему я не могу для разных объектов,т.е. типов, делать Resolve? Для типа по контейнеру?
Кодом людям нужно помогать!
Re[7]: как ресолвить не передавая ссылки на контейнер ( DI )
А фабрика-то откуда взялась? Ее же тоже надо resolve'вить. К тому же, мы можем настроить контейнер при создании(resolve)типа использовать фабрику. Т.е. от ссылки на контейнер с последующим resolve мы не ушли.
Кодом людям нужно помогать!
Re[9]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, okon, Вы писали:
O>после создания контейнера вызывается ресолв рута. O>Контейнер упоминается только в одном месте в методе CreateContainer и более он не требуется
O>
Он будет упоминаться в каждом классе, где как минимум требуется RootClass или еще чего. Т.е. опять же, его всюду придется инжектить, хотя бы через конструктор класса, там же, в конструкторе, получить от него
все необходимое и забыть про него.
Кодом людям нужно помогать!
Re[6]: как ресолвить не передавая ссылки на контейнер ( DI )
Здравствуйте, Doc, Вы писали:
Doc>PS: Кстати, service locator IMHO не всегда антипаттерн. В некоторых случаях он вполне применим. Но, наверное, это тема для отдельного разговора.
А подскажите в каких случаях применение сервис локатора оправдано?
Мне из моего опыта работы только 1 раз приходилось с этим сталкиваться когда под SharePoint писал — но там по другому вообще невозможно было.
Есть ли еще какие либо практические случаи оправданного применения сервис локатора
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте, okon, Вы писали:
O>>после создания контейнера вызывается ресолв рута. O>>Контейнер упоминается только в одном месте в методе CreateContainer и более он не требуется
O>>
S>Он будет упоминаться в каждом классе, где как минимум требуется RootClass или еще чего. Т.е. опять же, его всюду придется инжектить, хотя бы через конструктор класса, там же, в конструкторе, получить от него S>все необходимое и забыть про него.
Для RootClass не совсем я понял, например если нам нужен RootClass где-то внутри мы просто укажем его в конструкторе
Вот например, все разресолвится без передачи контейнера
public class RootClass
{
RootClass( Foo foo)
{
}
}
public class MyClass
{
public MyClass( RootClass root)
{
}
}
public class Foo
{
Foo( Func<MyClass> myClassFactory)
{
var myClass = myClassFactory();
}
}
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, okon, Вы писали:
O>Пишут что передавать ссылку на IContainer плохо, O>а как быть если нужно в процессе вычислений создать экземпляр класса и проинициализировать его поля, например с передачей контейнера, например O>Как такие сценарии правильно строятся без передачи и хранения ссылок на контейнеры ?
class a
{
private Func<B> _getB;
public A(Func<B> getB)
{
}
IEnumerable<B> CalculateSomething()
{
return Enumerable.Range(1,100).Select( i => _getB());
}
}