У меня есть структура, которая позволяет пользователям выполнять запросы к определенному источнику данных (игровая база данных Football Manager 2010, для тех, кто заинтересован).
В этом фреймворке у меня есть два разных режима работы моего фреймворка: режим реального времени и режим кэширования Я хочу, чтобы пользователи, которые используют эту платформу, могли переключаться, просто вызывая другой конструктор (например, new Context(Mode.Cached)
). Это должно быть единственным переключением, которое должен сделать пользователь, чтобы он мог по-прежнему иметь все те же вызовы Linq, но просто использовать режим кэширования, когда его приложение подходит лучше. Ясно.
Я решил, что использование PostSharp должно быть моим лучшим выбором, потому что:
- Создать аспект для каждого свойства (это уже было оформлено атрибутом)
- В этом аспекте проверьте, находимся ли мы в режиме
Cached
или Realtime
- Возвращает значение из памяти или из кэша
Ну, это работает. НО! Скорость не достаточно хороша. При выполнении 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 мс очень разумно, учитывая большое количество объектов.
Но! В 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 мс , более чем в 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; }
Как мне заставить это работать хорошо?!