配置autofac以忽略标记为过时的构造函数

时间:2011-06-20 06:24:24

标签: c# .net autofac obsolete

是否可以轻松配置autofac,以便只使用非过时的构造函数来解决?

例如,对于具有非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 个答案:

答案 0 :(得分:13)

我不相信有一种开箱即用的方式来配置Autofac来忽略Obsolete构造函数。但是,Autofac非常好,总有一种方法可以完成它。这里有两个选择:

选项1.告诉Autofac使用哪个构造函数

使用UsingConstructor registration extension方法执行此操作。

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

选项2.提供自定义IConstructorFinderFindConstructorsWith

Autofac有一个名为FindConstructorsWith的注册扩展方法。您可以将自定义IConstructorFinder传递给两个重载之一。您可以编写一个名为IConstructorFinder的简单NonObsoleteConstructorFinder,只返回构造函数,而不使用 Obsolete属性。

我写过这个课程并添加了你的样本的工作版本。您可以view the full code并将其用作灵感。 IMO选项这是更优雅的选项。我已将它添加到GitHub上的AutofacAnswers项目中。

注意:另一个重载需要BindingFlags。我不认为您可以使用BindingFlags指定属性要求。但是,您可能需要检查它。

答案 1 :(得分:0)

这是对bentayloruk的回答的延伸。我尝试了他的选项2 ,但它没有用。很快我注意到这是因为我使用的是AutoFac拦截器。 AutoFac将代理类类型传递给构造函数查找器,但这些构造函数不具有在基础类中的构造函数上定义的属性。

为了完成这项工作,我的代码比较了两个类的构造函数签名,以找到&#34;正确的&#34;构造函数并检查属性是否存在。

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库提供的扩展方法。