如何注入与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 非常简洁。
我想用 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 非常简洁。