Сконфигурируйте autofac, чтобы игнорировать конструкторы, помеченные как устаревшие - PullRequest
4 голосов
/ 20 июня 2011

Можно ли легко настроить автозапуск, чтобы он разрешался только с использованием устаревших конструкторов?

например, для класса с вспомогательным конструктором для кода без DI,

public class Example {

    public Example(MyService service) {
        // ...
    }

    [Obsolete]
    public Example() {
        service = GetFromServiceLocator<MyService>();
        // ...
    }
}

// ....

var builder = new ContainerBuilder();
builder.RegisterType<Example>();
// no MyService defined.
var container = builder.Build();

// this should throw an exception
var example = container.Resolve<Example>();

с просьбой разрешить autofac Пример. Если мы не зарегистрировали MyService, произойдет сбой.

Ответы [ 2 ]

13 голосов
/ 20 июня 2011

Я не верю, что есть из коробки способ настроить Autofac на игнорирование Obsolete конструкторов. Однако Autofac настолько хорош, что всегда есть способ сделать это :) Вот два варианта:

Вариант 1. Скажите Autofac, какой конструктор использовать

Сделайте это, используя UsingConstructor расширение регистрации метод.

builder.RegisterType<Example>().UsingConstructor(typeof(MyService));

Вариант 2. Укажите пользовательский IConstructorFinder до FindConstructorsWith

Autofac имеет метод расширения регистрации, называемый FindConstructorsWith. Вы можете передать пользовательский IConstructorFinder одной из двух перегрузок. Вы можете написать простой IConstructorFinder с именем NonObsoleteConstructorFinder, который будет возвращать только конструкторы без устаревшего атрибута.

Я написал этот класс и добавил рабочую версию вашего образца. Вы можете просмотреть полный код и использовать его как вдохновение. IMO - это более элегантный вариант. Я добавил его в свой проект AutofacAnswers на GitHub.

Примечание. Другая перегрузка принимает BindingFlags. Я не думаю, что вы можете указать требования к атрибутам, используя BindingFlags. Однако вы можете проверить это.

0 голосов
/ 27 октября 2014

Это продолжение ответа бентайлорука.Я попробовал его Вариант 2 , но он не сработал.Вскоре я заметил, что это потому, что я использую перехватчики AutoFac.AutoFac передает тип прокси-класса в конструктор поиска, но эти конструкторы не имеют атрибутов, определенных для конструкторов в базовом классе.

Для этой работы мой код сравнивает сигнатуры конструктора обоих классов, чтобы найти«правильный» конструктор и проверяет наличие атрибута.

public class NonObsoleteConstructorFinder : IConstructorFinder
{
    private readonly DefaultConstructorFinder _defaultConstructorFinder = new DefaultConstructorFinder();

    public ConstructorInfo[] FindConstructors(Type targetType)
    {
        // Find all constructors using the default finder
        IEnumerable<ConstructorInfo> constructors = _defaultConstructorFinder.FindConstructors(targetType);

        // If this is a proxy, use the base type
        if (targetType.Implements<IProxyTargetAccessor>())
        {
            // It's a proxy. Check for attributes in base class.
            Type underlyingType = targetType.BaseType;
            List<ConstructorInfo> constructorList = new List<ConstructorInfo>();

            // Find matching base class constructors
            foreach (ConstructorInfo proxyConstructor in constructors)
            {
                Type[] parameterTypes = proxyConstructor.GetParameters()
                                                        .Select(pi => pi.ParameterType)
                                                        .Skip(1)    // Ignore first parameter
                                                        .ToArray();

                ConstructorInfo underlyingConstructor = underlyingType.GetConstructor(parameterTypes);

                if (underlyingConstructor != null &&
                    !underlyingConstructor.HasAttribute<ObsoleteAttribute>())
                {
                    constructorList.Add(proxyConstructor);
                }
            }

            constructors = constructorList;
        }
        else
        {
            // It's not a proxy. Check for the attribute directly.
            constructors = constructors.Where(c => !c.HasAttribute<ObsoleteAttribute>());
        }

        return constructors.ToArray();
    }
}

Примечание 1: Skip(1) требуется, поскольку первый аргумент конструктора прокси имеет тип IInterceptor[].Это используется AutoFac для передачи перехватчиков.

Примечание 2: targetType.Implements<IProxyTargetAccessor>() и underlyingConstructor.HasAttribute<ObsoleteAttribute>() - это методы расширения, предоставляемые библиотекой Fasterflect.

...