如何访问拦截器上的扩展接口?

时间:2016-07-11 17:45:36

标签: c# dependency-injection ninject ninject-interception

我们在NinjectModule中为某些IInspection接口定义了多重绑定,如下所示:

private void BindCodeInspectionTypes()
{
    var inspections = Assembly.GetExecutingAssembly()
                              .GetTypes()
                              .Where(type => type.BaseType == typeof (InspectionBase));

    // multibinding for IEnumerable<IInspection> dependency
    foreach (var inspection in inspections)
    {
        var binding = Bind<IInspection>().To(inspection).InSingletonScope();
        binding.Intercept().With<TimedCallLoggerInterceptor>();
        binding.Intercept().With<EnumerableCounterInterceptor<InspectionResultBase>>();
    }
}

因此拦截器代理类型将用于IInspection。但是,某些inspection类型实现了IParseTreeInspection接口,扩展 IInspection

public interface IParseTreeInspection : IInspection
{
    ParseTreeResults ParseTreeResults { get; set; }
}

这产生的问题是使用这些消耗拦截器的代码 - 注入的代理类型可以理解为似乎对IParseTreeInspection一无所知,所以这个foreach循环不会#39} ; t甚至迭代一次:

var enabledParseTreeInspections = _inspections.Where(inspection => 
    inspection.Severity != CodeInspectionSeverity.DoNotShow 
 && inspection is IParseTreeInspection);

foreach (var parseTreeInspection in enabledParseTreeInspections)
{
    (parseTreeInspection as IParseTreeInspection).ParseTreeResults = parseTreeWalkResults;
}

有什么方法我可以多绑定IInspection(即构造函数注入IEnumerable<IInspection>仍然可以告诉IParseTreeInspection实例当Ninject是注射拦截器?

1 个答案:

答案 0 :(得分:0)

Here is one way to do it:

foreach (var inspection in inspections)
{
    if (typeof (IParseTreeInspection).IsAssignableFrom(inspection))
    {
        var binding = Bind<IParseTreeInspection>()
            .To(inspection)
            .InSingletonScope()
            .Named(inspection.FullName);

        binding.Intercept().With<TimedCallLoggerInterceptor>();
        binding.Intercept().With<EnumerableCounterInterceptor<InspectionResultBase>>();

        Bind<IInspection>().ToMethod(
            c => c.Kernel.Get<IParseTreeInspection>(inspection.FullName));
    }
    else
    {
        var binding = Bind<IInspection>().To(inspection).InSingletonScope();
        binding.Intercept().With<TimedCallLoggerInterceptor>();
        binding.Intercept().With<EnumerableCounterInterceptor<InspectionResultBase>>();
    }
}

This code checks if the type is assignable from IParseTreeInspection, i.e., it implements IParseTreeInspection, and if so, it creates a named binding from IParseTreeInspection to this type and configures the interception here. This will make sure that the proxy objects (created by the interceptor) will implement IParseTreeInspection. Then it creates another binding from IInspection to a delegate invocation that would use the kernel to resolve IParseTreeInspection via the the first binding (using the binding name).