Быстрый способ определить место, откуда была вызвана текущая процедура

Мне нужно найти способ определить место, из которого была вызвана текущая функция или процедура в классе. Неважно, является ли результат ячейкой памяти или номером устройства и строки, просто что-то уникальное для позиции, из которой пришел вызов.

Идентификатор местоположения необходимо вычислить быстро, так как он будет использоваться для принятия решения о доступности кэшированных данных.

Например.

type
  TTestObject = class
  public
    procedure TestProc;
    procedure TestCall;
  end;  

...

procedure TTestObject.TestProc;
begin
  TestCall; // "Point A" - Displays "Point A"
  TestCall; // "Point B" - Displays "Point B"
end;

procedure TTestObject.TestCall;
begin
  ShowMessage(SomehowGetTheCallingLineLocation); // Displays "Point A" or "Point B" depending on which line above it is called from
end;

end.

При вызове TestProc будет отображаться «точка A», а затем «точка B», независимо от того, сколько экземпляров TTestObject создано или где они находятся в памяти.

Функциональность будет использоваться при генерации SQL. В настоящее время я передаю GUID вызову, который генерирует SQL. Этот GUID используется для извлечения SQL из кэша, если он уже был сгенерирован.

  NewCommand(NewUpdateCriteria('{C43D3B79-9E73-4A4B-9E29-0553542AD0B2}').
    SetValue('AFIELD', AValue).
  Table
    ('ATABLE').
  Where
    (NewSQLComparitor
    ('ID', EqualTo, AID)));

Поиск местоположения вызова должен быть быстрым, иначе он сведет на нет улучшения скорости, которые мы должны увидеть при кэшировании SQL.

Компонент может в конечном итоге стать открытым исходным кодом, поэтому я не могу использовать какие-либо коммерческие сторонние компоненты. Я также хотел бы избежать зависимости от библиотек с открытым исходным кодом, таких как JEDI.


person norgepaul    schedule 01.06.2015    source источник
comment
Почему бы просто не передать аргумент? TTestObject.TestCall(UseCached : boolean); В качестве альтернативы любой объект, хранящий кэшированные данные, может отслеживать, есть ли у него достоверные данные. то есть: if FCacheDataStore.HasValidData then...   -  person J...    schedule 01.06.2015
comment
Мне также интересно, что вы подразумеваете под быстро. У вас есть определенные ограничения производительности?   -  person David Heffernan    schedule 01.06.2015
comment
@DavidHeffernan - я добавил немного больше информации о том, что я пытаюсь сделать.   -  person norgepaul    schedule 01.06.2015
comment
Кстати, ORM может в конечном итоге стать открытым исходным кодом, поэтому я не могу использовать какие-либо коммерческие сторонние компоненты. Я также хотел бы избежать зависимости от библиотек с открытым исходным кодом, таких как JEDI.   -  person norgepaul    schedule 01.06.2015
comment
@DavidHeffernan - Хорошо, я добавил комментарий к вопросам. Спасибо.   -  person norgepaul    schedule 01.06.2015


Ответы (1)


На основе вашего обновленного вопроса вам нужно только определить, что один вызов исходил из другого места, чем другой вызов. В этом случае вы можете использовать обратный адрес для идентификации вызывающего абонента. А адрес возврата можно получить вызовом недокументированной встроенной функции System.ReturnAddress.

Эта программа:

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

procedure Foo;
begin
  Writeln(IntToHex(NativeInt(ReturnAddress), 8));
end;

begin
  Foo;
  Foo;
  Foo;
  Foo;
end.

производит этот вывод на моей машине:

0041B491
0041B496
0041B49B
0041B4A0
person David Heffernan    schedule 01.06.2015
comment
+1, потому что это прямо и эффективно отвечает на вопрос, и вдвойне потому, что в результате я узнал что-то новое. Тем не менее, это похоже на действительно ужасное решение проблемы OP - такой уровень запутывания кода кажется совершенно неоправданным с учетом требований. Обычный способ получить информацию в методе — передать ее в качестве параметра. Я не вижу веских причин, почему это не сработает здесь. Если кто-то не пишет обработчик исключений или что-то в этом роде, условное ветвление на основе адреса возврата метода просто кажется кошмаром... - person J...; 01.06.2015
comment
@Дж... согласен. Это похоже на сложность и запутывание для незначительной выгоды. - person David Heffernan; 01.06.2015
comment
Кроме того, если метод проверки обратного адреса работает, то очевидно, что правильная ветвь известна во время компиляции. Если целью является максимизация производительности (порядка времени, необходимого для построения строки запроса), то простое написание отдельных методов было бы еще быстрее (полное удаление сравнения и ветвления). С одной линии звоните Foo;, с другой звоните FooCached;. - person J...; 01.06.2015
comment
@J...-Создание сложного SQL может занять много времени на сильно загруженном сервере. Идея состоит в том, чтобы позволить SQL быть построенным в первый раз, когда он нужен, а затем загружаться из кеша при последующих выполнениях. Знание того, где был создан SQL, позволяет нам кэшировать его без необходимости передачи дополнительных параметров или идентификаторов GUID. На мой взгляд, это не запутывает код, но позволяет нам полностью включить логику автоматического кэширования в классы генерации SQL. - person norgepaul; 01.06.2015
comment
@norgepaul Я понимаю мотивацию, я просто отказываюсь верить, что нет лучшего способа достичь своей цели. Если бы я нашел код такого рода в библиотеке базы данных, я был бы сильно мотивирован уничтожить его как можно быстрее. Это просто ужасный способ решить такую ​​проблему... - person J...; 02.06.2015
comment
@J... Не стесняйтесь предлагать альтернативное решение. Мы много думали об этом, и пока это лучшая идея, которую мы придумали. - person norgepaul; 02.06.2015
comment
@norgepaul На основании какой информации? Я понятия не имею, каковы ваши требования или архитектура. То, как вы это реализуете, полностью зависит от того, как вы собираетесь его использовать. Я уже предложил три метода в комментариях. Если они не подходят, из информации в вопросе непонятно, почему именно так. - person J...; 02.06.2015
comment
@J... Это моя точка зрения. Делать заявления вроде «Это просто ужасный способ решения такой проблемы без понимания нашей архитектуры» — это, на мой взгляд, слишком сильно. Если вам интересно, я буду рад дать вам взглянуть на код ORM, который мы пишем. Он находится в частном репозитории на GitHub. Мне просто нужно ваше имя пользователя. - person norgepaul; 02.06.2015
comment
@norgepaul Я могу представить множество реализаций с множеством разных потребностей. Я не могу представить, что кому-то нужно это в качестве решения. Если вы хотите опубликовать новый вопрос с четко определенным сценарием, требованиями и в качестве своего решения, я уверен, что вы получите много ценных отзывов. Однако я не думаю, что буду разрабатывать код для вас. - person J...; 02.06.2015
comment
@J... Чтобы было ясно, я не прошу вас разрабатывать код для меня. Я предложил вам взглянуть на код, если вы заинтересованы в понимании архитектуры. Я понимаю, что вы не можете представить сценарий, в котором можно было бы использовать этот шаблон, и это нормально. Спасибо за ваш вклад в любом случае. Привет, Пол - person norgepaul; 02.06.2015
comment
@norgepaul Нет, но я не собираюсь тратить день на копание в вашем исходном коде, чтобы генерировать для вас идеи. На мой взгляд, это это разработка программного обеспечения. Если вы готовы проделать всю работу по четкому представлению проблемы и связанных с ней ограничений, то я (и, конечно же, другие), несомненно, смогу дать полезный совет. Выбор за вами. - person J...; 02.06.2015
comment
Я думаю, что использование адреса возврата в качестве входных данных для функции очень необычно. Я никогда не припомню, чтобы видел это как идиому. Если это не широко используется, разве это не говорит о том, что это не очень хорошая идея. Что плохого в использовании аргументов? Прозрачный. Явный. Хорошо понятен всем читателям. - person David Heffernan; 02.06.2015
comment
@DavidHeffernan - В настоящее время мне нужно передать GUID для каждого уникального оператора SQL, чтобы иметь идентификатор для использования в кеше. Это потенциально очень подвержено ошибкам. например скопируйте/вставьте код и забудьте изменить GUID. Использование обратного адреса (насколько я понимаю) устранит любую возможность этого и будет на 100% прозрачным для конечного пользователя компонента. Я согласен, что это необычный способ получить нужные мне результаты, но не вижу в этом ничего опасного. - person norgepaul; 02.06.2015