Информация об изменениях

Сообщение Re[13]: О пользе Dependency Injection от 15.01.2021 23:01

Изменено 15.01.2021 23:02 Somescout

Re[13]: О пользе Dependency Injection
Здравствуйте, ·, Вы писали:

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



S>> Нет, не правильно: код остался полностью без изменений. Только вместо вызова вида:

S>>
var instance = serviceProvider.Get<SomeObject>()

·>Лукавство. Ты покажи _весь_ код, откуда ты взял serviceProvider?

В смысле? Взял из конструктора:
public class CallerObj {
  private readonly IServiceProvider serviceProvider;
  
  public CallerObj(IServiceProvider serviceProvider) {
    this.serviceProvider = serviceProvider;
  }

  public void Something() {
    var instance = serviceProvider.Get<SomeObject>();
  }
}


Если вам интересен вариант когда провайдер создаётся вручную, то примерно так (псевдокод):
public void Something() {
  var serviceBuilder = new ServiceBuilder();
  serviceBuilder
    .Bind<IDbContext,DbContext>(Scope.Request) // Просто для примера - понято что области запроса в данном случае нет
    .Bind<IAppConfig, AppConfig>(Scope.Singleton);

  serviceBuilder.Bind<SomeObject>(Scope.Transient); // Тут зависит от реализации DI: NInject умеет создавать произвольный объект,
                                                    //   если для него зарегистрированы все зависимости, MS DI (из NetCore) 
                                                    //   требует явной регистрации всех создаваемых объектов

  var serviceProvider = serviceBuilder.Build;
  
  var instance = serviceProvider.Get<SomeObject>();
}


Понятно что этот способ (т.е. через ServiceProvider) используется исключительно в том случае, когда инициализация SomeObject дорогая и сам объект используется он не всегда (я использую его только в контроллере, когда лишь часть экшенов использует его), в обычном случае будет:

public class CallerObj {
  private readonly SomeObject someObject;
  
  public CallerObj(SomeObject someObject) {
    this.someObject = someObject;
  }

  public void Something() {
    ...
  }
}



S>> Появилось

S>>
S>> var db = new DbContext();
S>> var config = new AppConfig();
S>> var instance = new SomeObject(db, config);
S>>

·>А вот это _весь_ код. Помещай его в main и запускай, будет работать. Притом быстро, без всяких рефлексий, рантайм-ошибок и километровых стек-трейсов.

Ну да, сравниете с ручным созданием ServiceProvider — разница в несколько строк. И да, у меня почему-то ни разу не возникало ситуации, когда проблемы с DI были с "рантайм-ошибок и километровых стек-трейсов" — обычно просто сообщение, что требуемый объект не зарегистрирован.

S>> Вот и всё различие. Внутренности SomeObject не менялись.

·>Не понял, а зачем их менять?
Это вы у IT спросите. Я с самого начала писал что там ничего не менялось.
Re[13]: О пользе Dependency Injection
Здравствуйте, ·, Вы писали:

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



S>> Нет, не правильно: код остался полностью без изменений. Только вместо вызова вида:

S>>
var instance = serviceProvider.Get<SomeObject>()

·>Лукавство. Ты покажи _весь_ код, откуда ты взял serviceProvider?

В смысле? Взял из конструктора:
public class CallerObj {
  private readonly IServiceProvider serviceProvider;
  
  public CallerObj(IServiceProvider serviceProvider) {
    this.serviceProvider = serviceProvider;
  }

  public void Something() {
    var instance = serviceProvider.Get<SomeObject>();
  }
}


Если вам интересен вариант когда провайдер создаётся вручную, то примерно так (псевдокод):
public void Something() {
  var serviceBuilder = new ServiceBuilder();
  serviceBuilder
    .Bind<IDbContext,DbContext>(Scope.Request) // Просто для примера - понято что области запроса в данном случае нет
    .Bind<IAppConfig, AppConfig>(Scope.Singleton);

  serviceBuilder.Bind<SomeObject>(Scope.Transient); // Тут зависит от реализации DI: NInject умеет создавать произвольный объект,
                                                    //   если для него зарегистрированы все зависимости, MS DI (из NetCore) 
                                                    //   требует явной регистрации всех создаваемых объектов

  var serviceProvider = serviceBuilder.Build();
  
  var instance = serviceProvider.Get<SomeObject>();
}


Понятно что этот способ (т.е. через ServiceProvider) используется исключительно в том случае, когда инициализация SomeObject дорогая и сам объект используется он не всегда (я использую его только в контроллере, когда лишь часть экшенов использует его), в обычном случае будет:

public class CallerObj {
  private readonly SomeObject someObject;
  
  public CallerObj(SomeObject someObject) {
    this.someObject = someObject;
  }

  public void Something() {
    ...
  }
}



S>> Появилось

S>>
S>> var db = new DbContext();
S>> var config = new AppConfig();
S>> var instance = new SomeObject(db, config);
S>>

·>А вот это _весь_ код. Помещай его в main и запускай, будет работать. Притом быстро, без всяких рефлексий, рантайм-ошибок и километровых стек-трейсов.

Ну да, сравниете с ручным созданием ServiceProvider — разница в несколько строк. И да, у меня почему-то ни разу не возникало ситуации, когда проблемы с DI были с "рантайм-ошибок и километровых стек-трейсов" — обычно просто сообщение, что требуемый объект не зарегистрирован.

S>> Вот и всё различие. Внутренности SomeObject не менялись.

·>Не понял, а зачем их менять?
Это вы у IT спросите. Я с самого начала писал что там ничего не менялось.