chrisdrobison
chrisdrobison

Reputation: 1323

Resolve type without creating object

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

builder.RegisterType<DeleteOrganization>().As<IDeleteOrganization>();

I'm implementing a SerializationBinder for a serialization project I'm doing and the BindToType method that I need to implement wants me to return a Type object. The BindToType method gives me an assemblyName and typeName (both strings) to help me create a type object. What I want to do is if the typeName is an interface, I want to ask Autofac what the concrete implementation Type is for that interface Type without actually having it create the object. Is that possible?

Upvotes: 9

Views: 2636

Answers (2)

t3chb0t
t3chb0t

Reputation: 18675

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.

Upvotes: 3

Danielg
Danielg

Reputation: 2699

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

Upvotes: 10

Related Questions