【问题标题】:Configure autofac to ignore constructors marked as obsolete配置 autofac 以忽略标记为过时的构造函数
【发布时间】:2011-06-20 06:24:24
【问题描述】:

是否可以轻松配置 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 应该会失败。

【问题讨论】:

    标签: c# .net autofac obsolete


    【解决方案1】:

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

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

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

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

    选项 2. 提供自定义 IConstructorFinderFindConstructorsWith

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

    我已经编写了这个类并添加了您的示例的工作版本。您可以view the full code 并将其用作灵感。 IMO 选项这是更优雅的选项。 我已将其添加到我在 GitHub 上的 AutofacAnswers 项目中。

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

    【讨论】:

    • 很棒的答案 :) 示例存储库是个好主意!
    • @Nic 谢谢!很棒的容器 :) 我刚刚将您添加为 AutofacAnswers 的合作者(如果出现提交的冲动)。
    • 是的,感谢您抽出宝贵的时间来构建如此出色的答案!
    • @nick-sonneveld 我很高兴。当我写原始答案时,我不知道 FindConstructorsWith,所以我也必须学习一些东西。 @nicholas-blumhardt 已经完成了所有艰苦的工作!
    【解决方案2】:

    这是对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&lt;IProxyTargetAccessor&gt;()underlyingConstructor.HasAttribute&lt;ObsoleteAttribute&gt;() 是 Fasterflect 库提供的扩展方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      • 2017-03-08
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      • 1970-01-01
      相关资源
      最近更新 更多