Разрешить тип без создания объекта - PullRequest
8 голосов
/ 28 февраля 2012

Вот моя проблема: у меня есть контейнер, в котором я регистрирую конкретные типы в качестве интерфейсов.

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

Я реализую SerializationBinder для проекта сериализации, который я делаю, и метод BindToTypeто, что мне нужно реализовать, хочет, чтобы я возвратил Type объект.Метод BindToType дает мне assemblyName и typeName (обе строки), чтобы помочь мне создать объект типа.Что я хочу сделать, так это если typeName - это интерфейс, я хочу спросить Autofac, какова конкретная реализация Type для этого интерфейса Type без фактического создания объекта.Это возможно?

Ответы [ 2 ]

10 голосов
/ 29 февраля 2012

Если вы используете RegisterType для регистрации своих услуг, это возможно. Я написал быстрый тест, который должен помочь вам извлечь нужные данные.


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));
            }
        }
    }
}
2 голосов
/ 29 сентября 2018

Вы можете очень красиво инкапсулировать метод @ Danielg , чтобы позволить Autofac внедрить список типов в конструктор. Это требует от вас реализации IRegistrationSource.

В моем случае я хотел получить все зарегистрированные типы, полученные из IConsoleCommand, например:

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

Я использовал простой DTO-List для переноса типов и T, для которого я хотел разрешить их:

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

Фактический источник регистрации реализован следующим образом, где <T> из TypeList<T> используется для соответствия типу интерфейса, который зарегистрирован и который мы хотим получить.

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

Наконец, вы должны добавить его к builder с помощью:

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

Теперь Autofac может разрешать типы с помощью внедрения зависимостей.

...