Is there a clean way to build generic type arguments in Autofac?

Viewed 39

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.

0 Answers
Related