65.9K
CodeProject 正在变化。 阅读更多。
Home

动态装饰器的性能

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2011年6月29日

CPOL

2分钟阅读

viewsIcon

17595

人们似乎对动态装饰器很感兴趣,但担心 .NET 远程调用的性能开销。在这里,我尝试澄清动态装饰器实现的一些疑点。

人们似乎对 动态装饰器 很感兴趣,但担心 .NET 远程调用的性能开销。在这里,我尝试澄清动态装饰器实现的一些疑点。

首先,动态装饰器没有使用运行时实现的 RealProxy。相反,它实现了自己的 RealProxyObjectProxy。因此,与运行时实现 RealProxy 相关的性能开销不适用于 ObjectProxy

其次,让我们深入 ObjectProxy 的代码,看看性能是否是一个问题。在动态装饰器中,目标对象的透明代理由 ObjectProxyFactory.CreateProxy 方法返回。该代理被运行时注册,以便在使用它调用方法时,运行时会拦截该调用。这种机制允许您通过重写 RealProxyInvoke 方法,在目标方法调用之前或之后添加预处理或后处理功能。

如果您进入代码,您会看到代理调用被解析为对 RealProxy.PrivateInvoke 的调用。RealProxy.PrivateInvoke 调用虚拟方法 RealProxy.Invoke,该方法被 ObjectProxy 重写。

因此,实际工作是在重写的 Invoke 方法内部完成的。在 ObjectProxyInvoke 方法内部,执行预处理代码,然后是目标方法,最后是后处理代码。

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 来说并非如此。如您在 ObjectProxyInvoke 代码中看到的,没有像跨应用域、跨上下文或上下文切换等代价高昂的操作。它只是预处理、目标方法调用和后处理的简单代码。这些都是有用的东西,而不是开销。

另一个性能开销的领域是拦截机制本身。拦截机制是如何实现的有点像一个黑盒子。但是,其背后的逻辑很简单:如果是一个透明代理对象,则调用其 RealProxyInvoke 方法。我想不出任何代价高昂的操作。
 
最终,动态装饰器的实现非常轻量级和精简。


© . All rights reserved.