在简单注入器中拦截方法调用时调用函数
本文关键字:调用 方法 函数 简单 注入器 | 更新日期: 2023-09-27 18:19:02
我想要实现的是拦截类的注入,并在类上调用特定的方法来改变它的行为。
我已经实现了在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
实例
为什么不使用装饰器而不是使用拦截?这通常更容易、更易于维护和更快。
下面是一个例子:
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
。由于装饰器直接依赖于MyClas
(而不是接口),所以MyClass
将被Simple Injector自动解析。
另一个选择是注册一个初始化式,如下所示:
container.RegisterInitializer<MyClass>(instance => {
instance.SetConnectionString();
});
初始化委托将在每次构建MyClass
实例后被调用。在这种情况下,行为有点不同,因为该方法不是每次都调用,而是只在构造期间调用。然而,通常情况下,这应该是足够的,因为您通常不应该在运行时更改服务,因为您会使事情复杂化。
好的,在发布问题后不久就找到了解决方案。
我改变了我的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);
}