Resolve type without creating object

前端 未结 2 604
攒了一身酷
攒了一身酷 2021-02-08 17:41

Here\'s my problem: I have a container where I register concrete types as interfaces.

builder.RegisterType().As

        
相关标签:
2条回答
  • 2021-02-08 18:11

    If you are using the RegisterType to register your services this is possible. I wrote a quick test that should help you extract the data you need.

    
    private interface IDeleteOrganization
    {
    
    }
    
    private class DeleteOrganization : IDeleteOrganization
    {
    
    }
    
    
    [TestMethod]
    public void CanResolveConcreteType()
    {
        var builder = new ContainerBuilder();
    
        builder.RegisterType()
            .As();
    
        using(var container = builder.Build())
        {
            var registration = container.ComponentRegistry
                .RegistrationsFor(new TypedService(typeof (IDeleteOrganization)))
                .SingleOrDefault();
    
            if (registration != null)
            {
                var activator = registration.Activator as ReflectionActivator;
                if (activator != null)
                {
                    //we can get the type
                    var type = activator.LimitType;
                    Assert.AreEqual(type, typeof (DeleteOrganization));
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-08 18:21

    You can very nicely encapsulate @Danielg's method so that you can let Autofac inject the type-list into a construtor. It requires you to implement the IRegistrationSource.

    In my case I wanted to get all registered types derived from IConsoleCommand like that:

    public Help(TypeList<IConsoleCommand> commands)
    {
        _commands = commands;
    }
    

    I used a simple DTO-List to carry the types and the T that I wanted to resolve them for:

    public class TypeList<T> : List<Type>
    {
        public TypeList(IEnumerable<Type> types) : base(types)
        {
        }
    }
    

    The actual registration source is implemented as following where the <T> from the TypeList<T> is used to match the type of interface that is registered and that we want to retrieve.

    internal class TypeListSource<T> : IRegistrationSource
    {
        public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
        {
            if (service is IServiceWithType swt && typeof(TypeList<T>).IsAssignableFrom(swt.ServiceType))
            {
                var registration =
                    new ComponentRegistration(
                        id: Guid.NewGuid(),
                        activator: new DelegateActivator(swt.ServiceType, (context, p) =>
                        {
                            var types =
                                context
                                    .ComponentRegistry
                                    .RegistrationsFor(new TypedService(typeof(T)))
                                    .Select(r => r.Activator)
                                    .OfType<ReflectionActivator>()
                                    .Select(activator => activator.LimitType);
                            return new TypeList<T>(types);
                        }),
                        services: new[] {service},
                        lifetime: new CurrentScopeLifetime(),
                        sharing: InstanceSharing.None,
                        ownership: InstanceOwnership.OwnedByLifetimeScope,
                        metadata: new Dictionary<string, object>()
                    );
                return new IComponentRegistration[] {registration};
            }
            // It's not a request for the base handler type, so skip it.
            else
            {
                return Enumerable.Empty<IComponentRegistration>();
            }
        }
    
        public bool IsAdapterForIndividualComponents => false;
    }
    

    Finally you have to add it to the builder with:

    builder.RegisterSource(new TypeListSource<IConsoleCommand>());
    

    Now Autofac can resolve the types with dependency injection.

    0 讨论(0)
提交回复
热议问题