动态装饰器的性能





5.00/5 (1投票)
人们似乎对动态装饰器很感兴趣,但担心 .NET 远程调用的性能开销。在这里,我尝试澄清动态装饰器实现的一些疑点。
人们似乎对 动态装饰器 很感兴趣,但担心 .NET 远程调用的性能开销。在这里,我尝试澄清动态装饰器实现的一些疑点。
首先,动态装饰器没有使用运行时实现的 RealProxy
。相反,它实现了自己的 RealProxy
– ObjectProxy
。因此,与运行时实现 RealProxy
相关的性能开销不适用于 ObjectProxy
。
其次,让我们深入 ObjectProxy
的代码,看看性能是否是一个问题。在动态装饰器中,目标对象的透明代理由 ObjectProxyFactory.CreateProxy
方法返回。该代理被运行时注册,以便在使用它调用方法时,运行时会拦截该调用。这种机制允许您通过重写 RealProxy
的 Invoke
方法,在目标方法调用之前或之后添加预处理或后处理功能。
如果您进入代码,您会看到代理调用被解析为对 RealProxy.PrivateInvoke
的调用。RealProxy.PrivateInvoke
调用虚拟方法 RealProxy.Invoke
,该方法被 ObjectProxy
重写。
因此,实际工作是在重写的 Invoke
方法内部完成的。在 ObjectProxy
的 Invoke
方法内部,执行预处理代码,然后是目标方法,最后是后处理代码。
public override IMessage Invoke(IMessage message)
{
object returnValue = null;
ReturnMessage returnMessage;
IMethodCallMessage methodMessage = (IMethodCallMessage)message;
MethodBase method = methodMessage.MethodBase;
AspectContext aspCtx = new AspectContext(target, methodMessage);
// Perform the preprocessing
if (HasMethod(method.Name) && preAspect != null)
{
try
{
preAspect.Action(aspCtx, preAspect.Parameters);
}
catch (Exception e)
{
if (!preAspect.SuppressException)
{
returnMessage = new ReturnMessage(e, methodMessage);
return returnMessage;
}
}
}
// Perform the call
try
{
returnValue = method.Invoke(target, methodMessage.Args);
}
catch (Exception ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
else
throw ex;
}
// Perform the postprocessing
if (HasMethod(method.Name) && postAspect != null)
{
try
{
postAspect.Action(aspCtx, postAspect.Parameters);
}
catch (Exception e)
{
if (!postAspect.SuppressException)
{
returnMessage = new ReturnMessage(e, methodMessage);
return returnMessage;
}
}
}
// Create the return message (ReturnMessage)
returnMessage = new ReturnMessage(returnValue, methodMessage.Args,
methodMessage.ArgCount, methodMessage.LogicalCallContext, methodMessage);
return returnMessage;
}
人们对远程调用的成本印象深刻,这归因于 RealProxy
的运行时实现,或者更具体地说,Invoke
方法的运行时实现。然而,对于 ObjectProxy
来说并非如此。如您在 ObjectProxy
的 Invoke
代码中看到的,没有像跨应用域、跨上下文或上下文切换等代价高昂的操作。它只是预处理、目标方法调用和后处理的简单代码。这些都是有用的东西,而不是开销。
另一个性能开销的领域是拦截机制本身。拦截机制是如何实现的有点像一个黑盒子。但是,其背后的逻辑很简单:如果是一个透明代理对象,则调用其 RealProxy
的 Invoke
方法。我想不出任何代价高昂的操作。
最终,动态装饰器的实现非常轻量级和精简。
