2

我想要实现的是拦截一个类的注入,并在该类上调用一个特定的方法来改变它的行为。

我已经实现了SimpleInjector 网站上给出的拦截器类,并且这是有效的,所以当类被拦截时我能够运行一些功能。

我的容器正在这样注册它:

container.InterceptWith<MyInterceptor>(type => type == typeof(IMyClass));

我拦截的课程如下所示:

public class MyClass : IMyClass
{
    private IAnotherClass m_class;
    public MyClass(IAnotherClass _class)
    {
         m_class = _class;
    }

    public void MethodToCall()
    {
         //changes properties on class
    }
}

我的拦截器类如下所示:

public class MyInterceptor : IInterceptor
{
    private readonly ILogger logger;

    public MyInterceptor(ILogger logger)
    {
        this.logger = logger;
    }

    public void Intercept(IInvocation invocation)
    {
        var watch = Stopwatch.StartNew();

        // Calls the decorated instance.
        invocation.Proceed();

        var decoratedType = invocation.InvocationTarget.GetType();

        logger.Trace(string.Format("{0} executed in {1} ms.",
            decoratedType.Name, watch.ElapsedTicks));
    }
}

我想要实现的是在拦截的 IMyClass 上调用一个方法。所以在拦截器中,调用MyClass.MethodToCall()

我试图在Intercept()方法中做这样的事情:

var classIntercepted = invocation.ReturnValue;
MethodInfo method = invocation.InvocationTarget.GetType().GetMethod("MethodToCall");
object magicValue = method.Invoke(classIntercepted, null);

但是,invocation.ReturnValue不是返回MyClass实例,而是返回IAnotherClass实例

4

2 回答 2

3

为什么不使用装饰器而不是使用拦截?这通常更容易、更易于维护和更快。

这是一个例子:

public class PropSetMyClassDecorator : IMyClass
{
    private MyClass decoratee;
    public PropSetMyClassDecorator(MyClass decoratee) {
        this.decoratee = decoratee;
    }

    public void MethodToCall() {
        this.decoratee.SetConnectionString();
        this.decoratee.MethodToCall();
    }
}

您可以按如下方式注册此装饰器:

container.Register<IMyClass, PropSetMyClassDecorator>();

请注意MyClass,我们只注册装饰器,而不是注册。由于装饰器直接依赖于MyClass(而不是接口)MyClass会被 Simple Injector 自动解析。

另一种选择是注册一个初始化器,如下所示:

container.RegisterInitializer<MyClass>(instance => {
    instance.SetConnectionString();
});

每次MyClass构造实例后都会调用初始化程序委托。在这种情况下,行为有点不同,因为不是每次都调用该方法,而是仅在构造期间调用。但是,通常这应该就足够了,因为您通常不应该在运行时更改服务,因为您会使事情复杂化。

于 2014-08-22T16:57:26.550 回答
2

好的,在发布问题后不久就找到了解决方案。

我将我的Intercept功能更改为以下内容:

    public void Intercept(IInvocation invocation)
    {
        // Calls the decorated instance.
        invocation.Proceed();

        var classIntercepted = invocation.InvocationTarget;
        MethodInfo method = invocation.InvocationTarget.GetType().GetMethod("SetConnectionString");
        method.Invoke(classIntercepted, null);
    }
于 2014-08-22T12:15:33.890 回答