5

是否可以轻松配置 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>();

如果我们没有注册 MyService,要求 autofac 解析 Example 应该会失败。

4

2 回答 2

14

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

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

使用UsingConstructor注册扩展方法执行此操作。

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

选项 2. 提供自IConstructorFinder定义FindConstructorsWith

Autofac 有一个注册扩展方法叫做FindConstructorsWith. 您可以将自定义传递给IConstructorFinder两个重载之一。您可以编写一个简单的IConstructorFinder调用NonObsoleteConstructorFinder,它只会返回没有Obsolete 属性的构造函数。

我已经编写了这个类并添加了您的示例的工作版本。您可以查看完整代码并将其用作灵感。 IMO 选项这是更优雅的选项。 我已将它添加到我在 GitHub 上的AutofacAnswers项目中。

注意:另一个重载采用 BindingFlags。我认为您不能使用BindingFlags. 但是,您可能需要检查一下。

于 2011-06-20T07:49:23.700 回答
0

这是对bentayloruk答案的扩展。我尝试了他的选项 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 库提供的扩展方法。

于 2014-10-27T14:16:42.827 回答