【问题标题】:Intercepting object with deep inheritance tree用深度继承树拦截对象
【发布时间】:2014-12-21 12:18:04
【问题描述】:

我拥有继承深度为 3 的对象结构。对象正在实现单个特定接口。接口的继承深度为 4。我的最终对象是通过统一 IoC 构建的。我需要拦截该对象中的每个公共方法(意味着无论它在哪个接口中定义),尽管无论我使用什么拦截器类型(InterfaceInterceptor/TransparentProxyInterceptor/VirtualMethodInterceptor),它总是只拦截在继承树的最终类中定义的方法。请看下面的对象结构示意图:

public interface IDevice {
    void Connect();
}

public interface ISerialDevice {
   void WriteCommand();
}

public interface IProtocolSerialDevice {
   void ExecuteProtocolCommand();
}

[MyHandler]
public interface ICustomSerialDevice {
   void ExecuteMyCommand();
}

public abstract class AbstractSerialDevice {
   public virtual void WriteCommand() {
        //omitted
   }
}

public abstract class AbstractProtocolSerialDevice : AbstractSerialDevice {
    public virtual void ExecuteProtocolCommand() {
         //omitted
    }
}


public class CustomSerialDevice : AbstractProtocolSerialDevice, ICustomSerialDevice {
      public virtual void ExecuteMyCommand() {
            //omitted
      }
}

public class MyHandlerAttribute : HandlerAttribute {
      public override ICallHandler CreateHandler(IUnityContainer container) {
         //omitted
      }
}

对象注册到统一容器如下:

container.RegisterType<ICustomSerialDevice, CustomSerialDevice>(
   new ContainerControlledLifetimeManager(),  new InjectionMethod(postConstructMethodName));

container.Configure<Interception>()
         .SetInterceptorFor<ICustomSerialDevice>(new TransparentProxyInterceptor());

不幸的是,我的拦截器总是只为ExecuteMyCommand() 方法调用。是否可以通过统一容器进行我正在争取的这种拦截?我正在慢慢考虑尝试通过 Spring.NET AOP 库来实现它。

【问题讨论】:

  • 您能否更新您的问题并显示您的对象图的外观(例如,如果您手动构建此对象图,代码会是什么样子)?您想添加哪些跨领域关注点?
  • 对象图相当多,因为它依赖于多个对象,而多个对象也依赖于其他一些对象;类 CustomSerialDevice 只是统一容器范围内的一个单例对象,尽管它对其他对象有多个依赖项,所以手动它可能类似于 new CustomSerialDevice {Dependency1 = new Dependency1 { Dependency2 = new Dependency2()} ....} .这是您在第一个问题中的意思吗?我需要对 CustomSerialDevice 的每个方法(也包括继承的方法)做一些一般的异常处理
  • 没错,但我宁愿看到你用类型的实际名称来展示它。问题是我经常看到开发人员由于他们的设计缺陷而依赖于拦截(例如与使用装饰器相比)来应用横切关注点。如果我们可以查看设计以及您如何尝试应用这些横切关注点,我们或许能够就设计提供反馈。

标签: c# unity-container aop unity-interception


【解决方案1】:

首先,我建议您尽可能使用 InterfaceInterceptor。它将为您提供最佳的灵活性和性能。当您无法使用 InterfaceInterceptor 时,回退到使用 VirtualMethodInterceptor。作为最后的手段,使用透明代理拦截器。见here

对于接口,handler 属性仅适用于在该接口上定义的方法(不继承)。因此,您可以通过使用 [MyHandler] 属性装饰所有 4 个接口来实现您所追求的。

对于具体类,handler 属性适用于所有继承的类型。因此,您可以通过使用 [MyHandler] 属性装饰顶部的 AbstractSerialDevice 来实现您的目标。您还可以在接口或具体类级别上装饰单个方法。

另外,在我看来,装饰一个具体的方法比装饰一个类型更容易被发现。虽然它有点冗长。


选项 1

// No MyHandler on any of the concrete classes

[MyHandler]
public interface IDevice
{ /* omitted */ }

[MyHandler]
public interface ISerialDevice : IDevice
{ /* omitted */ }

[MyHandler]
public interface IProtocolSerialDevice : ISerialDevice
{ /* omitted */ }

[MyHandler]
public interface ICustomSerialDevice : IProtocolSerialDevice
{ /* omitted */ }

选项 2

// No MyHandler on any of the interfaces nor derived classes

[MyHandler]
public abstract class AbstractSerialDevice : ISerialDevice
{ /* omitted */ }

选项 3

// No MyHandler on any of the interfaces nor abstract classes

public class CustomSerialDevice : AbstractProtocolSerialDevice, ICustomSerialDevice
{
    [MyHandler]
    public override void Connect()
    { base.Connect(); }

    [MyHandler]
    public override void WriteCommand()
    { base.WriteCommand(); }

    [MyHandler]
    public override void ExecuteProtocolCommand()
    { base.ExecuteProtocolCommand(); }

    [MyHandler]
    public void ExecuteMyCommand()
    { /*omitted*/ }
}

这些选项中的任何一个对您有用吗?

【讨论】:

  • 我对这个结果有点惊讶,所以感谢您指出一些意想不到的事情。了解这些怪癖很有价值。
  • 感谢您的出色回答。您的第三个选项非常适合我!
猜你喜欢
  • 1970-01-01
  • 2015-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
相关资源
最近更新 更多