I've been trying to inject an array of generic objects into a constructor for a generic type and can't find a clean way to do so.
I have a class like the below:
public sealed class RepositoryConsumer<T> : IRepositoryConsumer<T> Where T : BaseEntity
{
private readonly IOtherDependency _otherDependency;
private readonly IReadOnlyCollection<IRepository<T>> _regionalRepositories;
public RepositoryConsumer<T>(
IOtherDependency otherDependency,
IReadOnlyCollection<IRepository<T>> regionalRepositories)
{
_otherDependency = otherDependency;
_regionalRepositories = regionalRepositories;
}
...
I need to configure the IRepository<T> instances manually, because they will depend on other factors in the application. (e.g. certain regions available which are driven from config, types of T which are valid for only specific regions... etc.)
What I currently have to do configure this injection in an Autofac module is below, but it feels like there should be a better way.
private void BindRepositoryConsumers(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(IRepository<>)).As(typeof(IRepository<>));
builder.RegisterGeneric(typeof(RepositoryConsumer<>))
.As(typeof(IRepositoryConsumer<>))
.WithParameter(
(parameter, context) => ParameterTypeIsReadonlyCollectionOfIRepositories(parameter),
(parameter, context) =>
{
var type = parameter.ParameterType.GenericTypeArguments.First().GenericTypeArguments.First();
return GetType()
.GetMethod(nameof(CreateRepositories))
.MakeGenericMethod(type)
.Invoke(this, BindingFlags.Default, null, new object[] { context }, CultureInfo.InvariantCulture);
}).SingleInstance();
}
private static bool ParameterTypeIsReadonlyCollectionOfRepositories(ParameterInfo parameter)
{
return parameter.ParameterType.IsGenericType &&
parameter.ParameterType.GetGenericArguments().First().IsGenericType &&
typeof(IReadOnlyCollection<>)
.MakeGenericType(typeof(IRepository<>).MakeGenericType(parameter.ParameterType.GenericTypeArguments.First().GenericTypeArguments.First()))
.IsAssignableFrom(parameter.ParameterType);
}
public static IReadOnlyCollection<IRepository<T>> CreateRepositories<T>(IComponentContext context) where T : BaseEntity
{
var repositoryProvider = context.Resolve<IRepositoryProvider>();
var config = context.Resolve<IConfig>();
var regionalRepositories = config.Regions.Select(region => repositoryProvider.Create<T>(region));
return regionalRepositories;
}
Does anyone have a better/cleaner way of implementing this? I don't like dynamically invoking a method in there.