如何注入与Autofac具有两次相同接口的构造函数

How to inject constructor which has two times the same interface with Autofac

我想用 Autofac IoC 替换 Xamarin 3.2 应用程序中的 Unity IoC。因为我没有任何使用Autofac的经验,文档也没有解释我需要什么,所以我希望有人能帮助我。

我不知道,如果 class 在构造函数中获得两个相同类型但具有不同实现的接口,我必须如何配置构造函数注入。我的示例显示了两个存储库和一个外观。我想给两个存储库(相同的接口类型)外观构造函数。

我有什么

public class HostManager : IHost
    {
           public HostManager()
           {
           }
    }
    public class CustomerRepository : IRepository
    {
           public CustomerRepository(Context context)
           {
           }
    }
    public class AgentRepository : IRepository
    {
           public AgentRepository(Context context)
           {
           }
    }
    public class ToDoFacade : IFacade
    {
     public ToDoFacade(IHost host, IRepository agentRepository, IRepository customerRepository)
     {
     }
    }

    // IoC registration

    public class Registry
    {
        public Registry()
        {
     var builder = new ContainerBuilder();
     builder.RegisterType<HostManager>().As<IHost>().SingleInstance();
     builder.RegisterType<AgentRepository>().As<IRepository>().PreserveExistingDefaults();
     builder.RegisterType<CustomerRepository>().Named<IRepository>("Customer");

// How can I continue here?
     builder.RegisterType<ToDoFacade>().As<IFacade>().UsingConstructor(...);
        }
    }

你有什么办法可以解决吗?也欢迎链接到资源。

最佳蒂诺

如果你想用 Autofac 注入一个特定的实现,你可以简单地注入 class 本身,但是你需要通过在注册定义中添加 AsSelf 来让它自己注入:

builder.RegisterType<AgentRepository>().AsSelf().As<IRepository>();
builder.RegisterType<CustomerRepository>().AsSelf().As<IRepository>().Named<IRepository>("Customer");

那么,你可以直接注入:

public class ToDoFacade : IFacade
{
    public ToDoFacade(IHost host, AgentRepository agentRepository, CustomerRepository customerRepository)
    {
    }
}

另外,如果你想注入所有 IRepository 实现,你可以简单地做:

public ToDoFacade(IHost host, IEnumerable<IRepository> repositories)
{
}

您可以使用 ResolvedParameter 将某些命名注册注入您的 class。这是一个测试示例:

[Test]
public void InjectCertainRegistration()
{
    // Arrange 
    var registry = new Registry();

    // Act
    var facade = registry.GetFacade();

    // Assert
    Assert.IsInstanceOf<AgentRepository>(facade.AgentRepository);
    Assert.IsInstanceOf<CustomerRepository>(facade.CustomerRepository);
}

// IoC registration
public class Registry
{
    private readonly IContainer _root;

    public Registry()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<HostManager>().As<IHost>().SingleInstance();
        builder.RegisterType<AgentRepository>().As<IRepository>().Named<IRepository>("Agent").PreserveExistingDefaults();
        builder.RegisterType<CustomerRepository>().Named<IRepository>("Customer");

        builder.RegisterType<ToDoFacade>().As<IFacade>()
            .WithParameter(new ResolvedParameter((p, ctx) => p.Name == "agentRepository",
                (p, ctx) => ctx.ResolveNamed<IRepository>("Agent")))
            .WithParameter(new ResolvedParameter((p, ctx) => p.Name == "customerRepository",
                (p, ctx) => ctx.ResolveNamed<IRepository>("Customer")));

        _root = builder.Build();
    }

    public IFacade GetFacade()
    {
        return _root.Resolve<IFacade>();
    }
}

public class ToDoFacade : IFacade
{
    /// <summary>
    /// Just for testing
    /// </summary>
    public IRepository AgentRepository { get; }

    /// <summary>
    /// Just for testing
    /// </summary>
    public IRepository CustomerRepository { get; }

    public ToDoFacade(IHost host, IRepository agentRepository, IRepository customerRepository)
    {
        AgentRepository = agentRepository;
        CustomerRepository = customerRepository;
    }
}

public class CustomerRepository : IRepository
{
    public CustomerRepository()
    {
    }
}
public class AgentRepository : IRepository
{
    public AgentRepository()
    {
    }
}

public interface IFacade
{
    /// <summary>
    /// Just for testing
    /// </summary>
    IRepository AgentRepository { get; }

    /// <summary>
    /// Just for testing
    /// </summary>
    IRepository CustomerRepository { get; }
}

public class HostManager : IHost
{
    public HostManager()
    {
    }
}

public interface IHost { }

public interface IRepository { }

我稍微修改了你的例子。方法Registry.GetFacade()returns IFacade 来自容器的实例。我还添加了存储库属性以确保它们在测试中的类型。存储库的构造函数变得无参数只是为了简化示例。希望对你有帮助。

如果您已经注册了同一接口的两个实现,您可以向 class 注入一个 IEnumerable<IYourInterface>。如果您需要 select 基于某些条件的实施,autofac documentation 非常简洁。