I have a framework that allows users to do queries to a specific datasource (the Football Manager 2010 ingame database, for those of you interested).
In this framework, I have two different modes wherein my framework can run: realtime and cached mode. I want users who use this framework to be able to switch by just calling a different constructor (e.g. new Context(Mode.Cached)
). That should be the only switch a user should make, so he can still have all the same Linq calls, but just use Cached mode when his application fits better. Clear.
I had decided that using PostSharp should be my best choice because:
- Create an aspect on every property (that's already been decorated by an attribute)
- In that aspect, check whether we are in
Cached
orRealtime
mode - Return the value either from memory or from cache
Well that works. BUT! Speed is not good enough. When doing the following on 90.000 objects:
foreach (Player p in fm.Players)
{
int ca = (short)ProcessManager.ReadFromBuffer(p.OriginalBytes, PlayerOffsets.Ca, typeof(Int16));
}
It takes only 63 ms. (ReadFromBuffer is a highly optimized function which takes byte[], int, Type
and returns object
), 63 ms is very reasonable considering the large amounts of objects.
But! In PostSharp, I implemented quite the same using this:
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);
}
Now I call this using
foreach (Player p in fm.Players)
{
int ca = p.CA;
}
And it takes 782 ms, more than 10 times as much!
I created the aspect as:
[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
}
And the property is decorated like
[FMEntityAttribute(PlayerOffsets.Ca)]
public Int16 CA { get; set; }
How can I get this to perform well?!