как ресолвить не передавая ссылки на контейнер ( DI )
От: okon  
Дата: 19.05.18 04:20
Оценка:
Пишут что передавать ссылку на 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: как ресолвить не передавая ссылки на контейнер ( DI )
От: Doc Россия http://andrey.moveax.ru
Дата: 19.05.18 04:41
Оценка: +1
Здравствуйте, 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[2]: как ресолвить не передавая ссылки на контейнер ( DI )
От: okon  
Дата: 19.05.18 05:06
Оценка:
Здравствуйте, 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 может принимать массу аргументов которые хотелось бы брать из контейнера а не передавать явно.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 19.05.2018 5:07 okon . Предыдущая версия .
Re[3]: как ресолвить не передавая ссылки на контейнер ( DI )
От: Doc Россия http://andrey.moveax.ru
Дата: 19.05.18 05:22
Оценка:
Здравствуйте, okon, Вы писали:

O>Возможно, но пока не понятно как внутри будет выглядеть Factory.CreateSomething, ведь в ней придется либо создавать инстансы вручную, либо как-то ресолвить зависимости.


Фабрика создает вполне конкретные инстансы вполне конкретных (но только ей известных) типов.
Если надо создавать другие типы — создается другая фабрика.

Если посмотрите внимательно, то реализация Factory уже абстракция и прокинута в класс как интерфейс.
Метод CreateSomething должен возвращать интерфейс ISomething
Собственно больше абстракций / интерфейсов не требуется.
Re[3]: как ресолвить не передавая ссылки на контейнер ( DI )
От: _Raz_  
Дата: 19.05.18 05:26
Оценка:
Здравствуйте, 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 )
От: okon  
Дата: 19.05.18 05:35
Оценка:
_R_>
_R_>    //////////////////////////////////
    
_R_>    var b = new A(i => container.Resolve<B>(new TypedParameter(typeof(int), i)))
    
_R_>


Но ссылку на контейнер так и не понятно где брать, она существует только при ресолве корня и далее ее передавать не рекомендуют.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[4]: как ресолвить не передавая ссылки на контейнер ( DI )
От: okon  
Дата: 19.05.18 05:40
Оценка:
Здравствуйте, 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[5]: как ресолвить не передавая ссылки на контейнер ( DI )
От: Doc Россия http://andrey.moveax.ru
Дата: 19.05.18 05:52
Оценка: 4 (1)
Здравствуйте, 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[6]: как ресолвить не передавая ссылки на контейнер ( DI )
От: Doc Россия http://andrey.moveax.ru
Дата: 19.05.18 05:54
Оценка:
Кстати, зависимости же могут передаваться не только через конструктор, но и через свойства и параметры метода.
Поэтому еще есть вариант с

public ISomething CreateSomething (int i,IFoo foo, IBar bar) { … }

а они уже внедряются через конструктор вызывающей стороны
Re: как ресолвить не передавая ссылки на контейнер ( DI )
От: Sharov Россия  
Дата: 20.05.18 10:29
Оценка:
Здравствуйте, okon, Вы писали:

O>Пишут что передавать ссылку на IContainer плохо,


Кто пишет?Чем плохо?
Кодом людям нужно помогать!
Re[2]: как ресолвить не передавая ссылки на контейнер ( DI )
От: okon  
Дата: 20.05.18 22:15
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, okon, Вы писали:


O>>Пишут что передавать ссылку на IContainer плохо,


S>Кто пишет?Чем плохо?


Кто уже не помню, но смысл был такой что весь граф зависимостей должен определяться в одном месте, а не быть размазан по коду.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[3]: как ресолвить не передавая ссылки на контейнер ( DI )
От: Sharov Россия  
Дата: 21.05.18 09:50
Оценка:
Здравствуйте, okon, Вы писали:

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


Это логично, но ссылку на контейнер надо же передавать, иначе как объекты будут создаваться?
Кодом людям нужно помогать!
Re: как ресолвить не передавая ссылки на контейнер ( DI )
От: GarryIV  
Дата: 21.05.18 11:12
Оценка:
Здравствуйте, okon, Вы писали:

O>Пишут что передавать ссылку на IContainer плохо,

O>а как быть если нужно в процессе вычислений создать экземпляр класса и проинициализировать его поля, например с передачей контейнера, например
O>Как такие сценарии правильно строятся без передачи и хранения ссылок на контейнеры ?

В Спринге это делается как то так


@Bean
public FactoryType factoryType(Dependency1 dep1, Dependency2 dep2) {
  return new FactoryType(dep1, dep2);
}


Тут по сути фабрика которая создает объект типа FactoryType с зависимостями dep1, dep2.

ЗЫЖ Этот метод явно никто не вызывает, он вызывается контейнером и передает туда необходимые зависимости.
WBR, Igor Evgrafov
Отредактировано 21.05.2018 11:14 GarryIV . Предыдущая версия .
Re[4]: как ресолвить не передавая ссылки на контейнер ( DI )
От: okon  
Дата: 21.05.18 16:08
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, okon, Вы писали:


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


S>Это логично, но ссылку на контейнер надо же передавать, иначе как объекты будут создаваться?


Подразумевается что Resolve делается один раз для корневого объекта, а остальные зависимости сидят в конструкторах и вычисляются автоматом.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[5]: как ресолвить не передавая ссылки на контейнер ( DI )
От: Sharov Россия  
Дата: 21.05.18 16:39
Оценка:
Здравствуйте, okon, Вы писали:

O>Подразумевается что Resolve делается один раз для корневого объекта, а остальные зависимости сидят в конструкторах и вычисляются автоматом.


А почему я не могу для разных объектов,т.е. типов, делать Resolve? Для типа по контейнеру?
Кодом людям нужно помогать!
Re[6]: как ресолвить не передавая ссылки на контейнер ( DI )
От: okon  
Дата: 23.05.18 10:51
Оценка: +1
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, okon, Вы писали:


O>>Подразумевается что Resolve делается один раз для корневого объекта, а остальные зависимости сидят в конструкторах и вычисляются автоматом.


S>А почему я не могу для разных объектов,т.е. типов, делать Resolve? Для типа по контейнеру?


Основная идея я так понимаю делать это все при настройке контейнера, в том числе если что-то надо ресолвить когда-то потом, создается функция как-то так


void RegisterTypesInContainer()
{

    ...
    container.Register<Func<MyClass>>( ()=> container.Resolve<MyClass>() );

    ...
}



и потом где-то в коде вместо того чтобы делать container.Resolve()



public class Foo
{
    Foo( Func<MyClass> myClassFactory )
    {
       MyClass instance = myClassFactory();
    }
}



вместо Func<MyClass>() можно делать какие-нибудь IMyClassFactory
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[7]: как ресолвить не передавая ссылки на контейнер ( DI )
От: Sharov Россия  
Дата: 23.05.18 13:35
Оценка:
Здравствуйте, okon, Вы писали:



O>и потом где-то в коде вместо того чтобы делать container.Resolve()



O>

O>public class Foo
O>{
O>    Foo( Func<MyClass> myClassFactory )
O>    {
O>       MyClass instance = myClassFactory();
O>    }
O>}

O>


А фабрика-то откуда взялась? Ее же тоже надо resolve'вить. К тому же, мы можем настроить контейнер при создании(resolve)типа использовать фабрику. Т.е. от ссылки на контейнер с последующим resolve мы не ушли.
Кодом людям нужно помогать!
Re[8]: как ресолвить не передавая ссылки на контейнер ( DI )
От: okon  
Дата: 24.05.18 04:12
Оценка: 5 (1)
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, okon, Вы писали:




O>>и потом где-то в коде вместо того чтобы делать container.Resolve()



O>>

O>>public class Foo
O>>{
O>>    Foo( Func<MyClass> myClassFactory )
O>>    {
O>>       MyClass instance = myClassFactory();
O>>    }
O>>}

O>>


S>А фабрика-то откуда взялась? Ее же тоже надо resolve'вить. К тому же, мы можем настроить контейнер при создании(resolve)типа использовать фабрику. Т.е. от ссылки на контейнер с последующим resolve мы не ушли.



Она разресолвится автоматом, я же в примере ее зарегистрировал там где региструется все, Foo будет где-то в иерархии и он разресолвится автоматом.

Например самая простая иерархия


public class RootClass
{
    public RootClass( Foo foo )
    {
       ...
    }
}



после создания контейнера вызывается ресолв рута.
Контейнер упоминается только в одном месте в методе CreateContainer и более он не требуется


void CreateContainer()
{

    container.Register<Func<MyClass>>( () => container.Resolve<MyClass>());

     Root = container.Resolve<RootClass>(); 
}
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[9]: как ресолвить не передавая ссылки на контейнер ( DI )
От: Sharov Россия  
Дата: 24.05.18 11:02
Оценка:
Здравствуйте, okon, Вы писали:

O>после создания контейнера вызывается ресолв рута.

O>Контейнер упоминается только в одном месте в методе CreateContainer и более он не требуется

O>
O>void CreateContainer()
O>{

O>    container.Register<Func<MyClass>>( () => container.Resolve<MyClass>());

O>     Root = container.Resolve<RootClass>(); 
O>}

O>


Он будет упоминаться в каждом классе, где как минимум требуется RootClass или еще чего. Т.е. опять же, его всюду придется инжектить, хотя бы через конструктор класса, там же, в конструкторе, получить от него
все необходимое и забыть про него.
Кодом людям нужно помогать!
Re[6]: как ресолвить не передавая ссылки на контейнер ( DI )
От: Jericho113 Украина  
Дата: 24.05.18 11:29
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>PS: Кстати, service locator IMHO не всегда антипаттерн. В некоторых случаях он вполне применим. Но, наверное, это тема для отдельного разговора.

А подскажите в каких случаях применение сервис локатора оправдано?
Мне из моего опыта работы только 1 раз приходилось с этим сталкиваться когда под SharePoint писал — но там по другому вообще невозможно было.

Есть ли еще какие либо практические случаи оправданного применения сервис локатора
NetDigitally yours ....
Отредактировано 24.05.2018 11:30 Jericho113 . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.