Autofac从Container解析构造函数实例?

Mik*_*ike 3 c# dependency-injection autofac

如何在不传递实际实例的情况下注册另一种类型作为其构造的一部分的类型.假设我注册了两个ISurface类型.我想注册一辆车,但我不想传递一个全新的实例.我想使用已经定义的一个表面.

根据文件,他们说:

  • Autofac看到IDateWriter映射到TodayWriter,因此开始创建TodayWriter.
  • Autofac发现TodayWriter在其构造函数中需要IOutput.
  • Autofac看到IOutput映射到ConsoleOutput,因此创建一个新的ConsoleOutput实例.

那么为什么我必须在登记汽车时通过高速公路的实例?鉴于我已经注册了两个Surfaces,如何指定现有曲面?

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());
Run Code Online (Sandbox Code Playgroud)

为什么我需要通过一个新的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}");
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 7

你可以在这里做几件事:

选项1

这与您已有的一致.你仍然可以使用.WithParameter()但是传入一个ResolvedParameter实例来解释要查找的参数以及如何完成参数:

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

传递给ResolvedParameter构造函数的第一个委托提供了一种查找要实现的参数的方法,第二个委托使用它IComponentContext来解析HighwayAutofac容器中的实例.

或者WithParameter(),您可以使用重载,而无需显式创建ResolvedParameter:

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

选项2

此选项使用lambda表达式注册:

builder.Register( ( ctx ) => new Car( ctx.ResolveNamed<ISurface>( "Highway" ) ) ).Named<IVehicle>( "Car" );
Run Code Online (Sandbox Code Playgroud)

在这里你可以看到我传递了一个代表我的工厂函数的lambda,它将再次使用它IComponentContext来解析HighwayAutofac容器.

注意

我还从您的问题中读到,您希望ISurface每次请求时都使用相同的实例.如果这是您想要的,那么您需要更新您的ISurface注册以包括.SingleInstance():

builder.RegisterType<Highway>().Named<ISurface>( "Highway" ).SingleInstance();
builder.RegisterType<Ocean>().Named<ISurface>( "Ocean" ).SingleInstance();
Run Code Online (Sandbox Code Playgroud)

注册的默认生命周期InstancePerDependency意味着Autofac解析器每次请求时都会提供该对象的新实例.SingleInstance本质上是一个单身人士.您只会创建一个实例,并且每个请求都会返回该实例.这是该信息的链接