Как внедрить конструктор, который имеет два раза один и тот же интерфейс с Autofac - PullRequest
0 голосов
/ 21 сентября 2018

Я хочу заменить свой Unity IoC в приложении Xamarin 3.2 на Autofac IoC.Поскольку у меня нет никакого опыта работы с Autofac и документация не объясняет, что мне нужно, я надеюсь, что кто-нибудь может мне помочь.

Я не знаю, как мне нужно настроить внедрение конструктора, еслиКласс получает два интерфейса одного типа в конструкторе, но с разными реализациями.Мой пример показывает два хранилища и фасад.Я хочу дать оба хранилища (один и тот же тип интерфейса) конструктор фасада.

Что у меня есть

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(...);
        }
    }

У вас есть идея для меня, как я могу ее решить?Ссылки на ресурсы также приветствуются.

Best Tino

Ответы [ 3 ]

0 голосов
/ 25 сентября 2018

Вы можете использовать ResolvedParameter для внедрения определенных именованных регистраций в ваш класс.Вот пример с тестом:

[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() возвращает IFacade экземпляр из контейнера.Также я добавил свойства репозитория, чтобы убедиться в их типах в тестах.Конструктор репозиториев стал без параметров просто для упрощения примера.Надеюсь, это поможет.

0 голосов
/ 11 октября 2018

Если вы зарегистрировали две реализации одного и того же интерфейса, вы можете добавить IEnumerable<IYourInterface> в класс.Если вам нужно выбрать реализацию, основанную на некоторых условиях, документация autofac довольно аккуратна.

0 голосов
/ 22 сентября 2018

Если вы хотите внедрить конкретную реализацию с помощью Autofac, вы можете просто внедрить сам класс, но вам нужно будет сделать его внедряемым отдельно, добавив 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)
{
}
...