如何快速获得这个?

时间:2009-11-17 23:09:18

标签: c# aop postsharp

我有一个框架,允许用户对特定数据源进行查询(对于那些感兴趣的人,可以使用Football Manager 2010游戏数据库)。

在这个框架中,我有两种不同的模式,我的框架可以运行:实时和缓存模式。我希望使用此框架的用户只需调用不同的构造函数即可切换(例如new Context(Mode.Cached))。这应该是用户应该进行的唯一切换,因此他仍然可以拥有所有相同的Linq调用,但只需在他的应用程序更适合时使用缓存模式。清除。

我已经决定使用PostSharp应该是我的最佳选择,因为:

  • 在每个属性上创建一个方面(已经由属性修饰)
  • 在此方面,请检查我们是否处于CachedRealtime模式
  • 从内存或缓存中返回值

那很有效。但!速度不够好。在90.000对象上执行以下操作时:

foreach (Player p in fm.Players)
{
    int ca = (short)ProcessManager.ReadFromBuffer(p.OriginalBytes, PlayerOffsets.Ca, typeof(Int16));
}

只需63毫秒。 (ReadFromBuffer是一个高度优化的函数,需要byte[], int, Type并返回object),考虑到大量的对象,63 ms是非常合理的。

但是!在PostSharp中,我用这个实现了完全相同:

    public override void OnInvocation(MethodInvocationEventArgs eventArgs)
    {
        if (eventArgs.Method.Name.StartsWith("~get_"))
        {
            if (Global.DatabaseMode == DatabaseModeEnum.Cached)
            {
                byte[] buffer = ((BaseObject)eventArgs.Instance).OriginalBytes;

                eventArgs.ReturnValue =
                        ProcessManager.ReadFromBuffer(buffer, this.Offset, eventArgs.Method.ReturnType);
            }

现在我用

来调用它
foreach (Player p in fm.Players)
{
    int ca = p.CA;
}

它需要 782 ms ,超过10倍!

我创建了方面:

[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method, PersistMetaData = true)]
internal class FMEntityAttribute : OnMethodInvocationAspect
{
    public FMEntityAttribute(int offset, int additionalStringOffset)
    {
        this.Offset = offset;
        this.AdditionalStringOffset = additionalStringOffset;
    }
    //blah blah AOP code
}

该物业的装饰如

    [FMEntityAttribute(PlayerOffsets.Ca)]
    public Int16 CA { get; set; }

我怎样才能让它表现良好?!

4 个答案:

答案 0 :(得分:2)

使用PostSharp 2.0的LocationInterceptionAspect可以获得更好的结果。

但是你应该避免在运行时使用eventArgs.Method.ReturnType;而是获取方法RuntimeInitialize中的值并将其存储在字段中。因此,在运行时不使用System.Reflection。

答案 1 :(得分:1)

  1. 使用CompileTimeValidate方法检查其属性是否为

答案 2 :(得分:1)

使用工厂方法创建上下文,而不是使用new Context(Mode.Cached))创建上下文。然后在两个不同的类中实现您的两个行为,这些类共享他们需要的抽象超类型。使用方面和反射来解决没有简单直接解决方案的问题。


替换

[FMEntityAttribute(PlayerOffsets.Ca)] public Int16 CA { get; }

public Int16 CA { get { return PlayerAttrs.Ca.Get(this); } }

其中PlayerAttrs有一个运算符Int16,可以根据需要将自身转换为Int16,具有所需的偏移量,并执行适当的缓存/非缓存查找。

答案 3 :(得分:0)

反思可能很昂贵。您可能尝试的一件事实际上是在运行时为此类编译包装器,并保存您当前拥有的每次调用命中。