提高 Castle 的 DynamicProxy 的性能?

发布于 2024-10-02 09:39:30 字数 1980 浏览 0 评论 0原文

我目前正在尝试实现一个 AOP 系统,以向对象的修饰属性添加自动审核(由 INotifyPropertyChanged 的​​扩展版本完成)。自动审核包含 propertyName 的旧值和新值。

我目前正在使用 Castle 的 DynamicProxy2,因为有很棒的教程(即这个:: http://kozmic.pl/archive/2009/04/27/castle-dynamic-proxy-tutorial.aspx)了解如何使用该工具。我为每个为该类型装饰的属性生成一个委托。表达式树生成类似这样的东西::(注意,我认为这比粘贴我的表达式树代码更容易,因为我的代码依赖于类型安全的反射库和大量静态变量)

.Lambda #Lambda1<System.Action`1[Castle.DynamicProxy.IInvocation]>(Castle.DynamicProxy.IInvocation $invocation) {
    .Block(
        DutchTest.MixinTest $target,
        System.Object $argument,
        System.DateTime $newValue,
        System.DateTime $oldValue) {
        $target = (DutchTest.MixinTest).Call $invocation.get_InvocationTarget();
        $newValue = .Unbox($argument = .Call $invocation.GetArgumentValue(.Default(System.Int32)));
        .If (
            .Call (.Call System.Collections.Generic.EqualityComparer`1[System.DateTime].get_Default()).Equals(
                $oldValue = .Call $target.get_Created(),
                $newValue)
        ) {
            .Default(System.Void)
        } .Else {
            .Block() {
                .Call $invocation.Proceed();
                .Call ($target .As Dutch.Auditing.INotifyAuditedChange).OnPropertyChanged(.New Dutch.Auditing.AuditEventArgs(
                        "Created",
                        (System.Object)$oldValue,
                        $argument))
            }
        }
    }
}

然后我有一个自定义选择器,它选择 DelegateInterceptor (一个实现 IInterceptor 的类,其 Intercept 方法只是调用委托。我还有一个自定义钩子,它仅选择我计划委托的属性(因此我避免了代理 get 的成本) 。

不幸的是,即使采取了所有这些预防措施,我仍然发现每个属性集的性能都会受到很大的影响(手动执行该逻辑大约需要 0.4 个刻度,如果使用动态代理则需要大约 2.2 个刻度,如果使用动态代理则需要 2.8 个刻度) 我必须混合 INotifyAuditedChange 的逻辑,并且会引发一个事件)。这不会太糟糕,但作为我的要求的一部分,我正在查看大量被修改的对象

。 ,我使用 typebuilder 的计划失败了(用 Reflection.Emit 编写代码太难了,显然 CompileToMethod 不能用于实例方法),我是否缺少一些技巧来提高 DynamicProxy2 的性能?

I'm currently trying to implement an AOP system to add automatic audits to decorated attributes of objects (done by an extended version of INotifyPropertyChanged). The automatic audit contains the propertyName it's old value and the new value.

I'm currently using Castle's DynamicProxy2 as there are excellent tutorials (namely this one:: http://kozmic.pl/archive/2009/04/27/castle-dynamic-proxy-tutorial.aspx) on how to use the tool. I generate a delegate for each property that is decorated for the type. The expression tree generates something like this:: (note I figure this is easier than pasting my expression tree code as my code relies on a type-safe reflection library and lots of static variables)

.Lambda #Lambda1<System.Action`1[Castle.DynamicProxy.IInvocation]>(Castle.DynamicProxy.IInvocation $invocation) {
    .Block(
        DutchTest.MixinTest $target,
        System.Object $argument,
        System.DateTime $newValue,
        System.DateTime $oldValue) {
        $target = (DutchTest.MixinTest).Call $invocation.get_InvocationTarget();
        $newValue = .Unbox($argument = .Call $invocation.GetArgumentValue(.Default(System.Int32)));
        .If (
            .Call (.Call System.Collections.Generic.EqualityComparer`1[System.DateTime].get_Default()).Equals(
                $oldValue = .Call $target.get_Created(),
                $newValue)
        ) {
            .Default(System.Void)
        } .Else {
            .Block() {
                .Call $invocation.Proceed();
                .Call ($target .As Dutch.Auditing.INotifyAuditedChange).OnPropertyChanged(.New Dutch.Auditing.AuditEventArgs(
                        "Created",
                        (System.Object)$oldValue,
                        $argument))
            }
        }
    }
}

I then have a custom selector which choses the DelegatedInterceptor (a class that implements IInterceptor, whose Intercept method is just to invoke the delegate. I also have a custom hook that only chooses the the properties that I plan on delegating (so I avoid the cost of proxying the get method).

Unfortunately, even with all these precautions I am looking at a substantial performance hit on every property set (it takes approximately .4 ticks to do that logic by hand and about 2.2 ticks if I do it with dynamic proxy, 2.8 ticks if I have to mixin the logic for INotifyAuditedChange and an event would be raised). This wouldn't be so bad, but as part of my requirements I am looking at very large amount of objects being modified.

Unfortunately, my plans to use typebuilder failed (it is way too hard to write the code with Reflection.Emit and apparently CompileToMethod cannot be used for instance methods), is there some tricks I am missing to improve the performance of DynamicProxy2?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文