是否可以轻松配置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,则应该失败。
答案 0 :(得分:13)
我不相信有一种开箱即用的方式来配置Autofac来忽略Obsolete
构造函数。但是,Autofac非常好,总有一种方法可以完成它。这里有两个选择:
选项1.告诉Autofac使用哪个构造函数
使用UsingConstructor
registration extension方法执行此操作。
builder.RegisterType<Example>().UsingConstructor(typeof(MyService));
选项2.提供自定义IConstructorFinder
至FindConstructorsWith
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库提供的扩展方法。