Автоматическое разрешение экземпляра конструктора из контейнера?

#c# #dependency-injection #autofac

#c# #внедрение зависимостей #autofac

Вопрос:

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

Согласно документации, в которой они указаны :

  • Autofac видит, что IDateWriter сопоставляется с TodayWriter, поэтому начинает создавать TodayWriter.
  • Autofac видит, что TodayWriter нуждается в IOutput в своем конструкторе.
  • Autofac видит, что IOutput сопоставляется с ConsoleOutput, поэтому создает новый экземпляр ConsoleOutput.

Тогда почему я должен передавать экземпляр Highway при регистрации автомобиля? Учитывая, что у меня зарегистрированы две поверхности, как мне указать существующую поверхность?

 var builder = new ContainerBuilder();
builder.RegisterType<Highway>().Named<ISurface>("Highway");
builder.RegisterType<Ocean>().Named<ISurface>("Ocean");

builder.RegisterType<Car>().Named<IVehicle>("Car").WithParameter("surface", new Highway());
  

Зачем мне нужно передавать новую магистраль()?

Вот мои модели.

 public interface IVehicle
{
    void Move();
}

public interface ISurface
{
    string SurfaceType { get; }
}

public class Highway : ISurface
{
    public string SurfaceType => "Pavement";
}

public class Ocean : ISurface
{
    public string SurfaceType => "Ocean"
}

public class Car : IVehicle
{
    private ISurface _surface;

    public Car(ISurface surface)
    {
        _surface = surface;
    }

    public void Move()
    {
        Console.WriteLine($"I'm traveling at high speeds across {_surface.SurfaceType}");
    }
}
  

Ответ №1:

Здесь есть пара вещей, которые вы можете сделать:

Вариант 1

Это соответствует тому, что у вас уже есть. Вы все равно можете использовать .WithParameter() , но вместо этого передаете ResolvedParameter экземпляр, чтобы объяснить, какой параметр нужно найти и как выполнить параметр:

 builder.RegisterType<Car>().Named<IVehicle>( "Car" )
    .WithParameter(
        new ResolvedParameter(
            ( pInfo, ctx ) => pInfo.Name == "surface",
            ( pInfo, ctx ) => ctx.ResolveNamed<ISurface>( "Highway" )
            )
    );
  

Первый делегат, переданный ResolvedParameter конструктору, предоставляет способ найти параметр для выполнения, а второй делегат использует IComponentContext для разрешения Highway экземпляра из контейнера Autofac.

В качестве альтернативы существует перегрузка WithParameter() , которую вы можете использовать без необходимости явно создавать ResolvedParameter :

 builder.RegisterType<Car>().Named<IVehicle>( "Car" )
    .WithParameter(
    ( pInfo, ctx ) => pInfo.Name == "surface",
    ( pInfo, ctx ) => ctx.ResolveNamed<ISurface>( "Highway" ) );
  

Вариант 2

Этот параметр использует регистрацию с помощью лямбда-выражения:

 builder.Register( ( ctx ) => new Car( ctx.ResolveNamed<ISurface>( "Highway" ) ) ).Named<IVehicle>( "Car" );
  

Здесь вы можете видеть, что я передаю лямбда-выражение, представляющее мою заводскую функцию, которая снова будет использовать IComponentContext для разрешения Highway из контейнера Autofac.

ПРИМЕЧАНИЕ

Я также прочитал из вашего вопроса, что вы хотели один и тот же экземпляр ISurface каждый раз, когда вы его запрашивали. Если это то, что вы хотите, вам нужно будет обновить свои ISurface регистрации, чтобы включить .SingleInstance() :

 builder.RegisterType<Highway>().Named<ISurface>( "Highway" ).SingleInstance();
builder.RegisterType<Ocean>().Named<ISurface>( "Ocean" ).SingleInstance();
  

Время жизни по умолчанию, указанное для регистраций InstancePerDependency , означает, что распознаватель Autofac будет предоставлять новый экземпляр объекта каждый раз, когда он запрашивается. SingleInstance по сути, является синглтоном. Вы создадите только один экземпляр, и этот экземпляр будет возвращаться при каждом запросе. Вот ссылка на эту информацию

Комментарии:

1. Красивое объяснение.