Подтвердить что ты не робот

Предотвращение внедрения JIT по методу

У меня сложилась уникальная ситуация. Я работаю над библиотекой с открытым исходным кодом для отправки электронной почты. В этой библиотеке мне нужен надежный способ получить метод вызова. Я сделал это с помощью StackTrace путем анализа объектов StackFrame внутри него. Это работает без проблем в проекте debug-mode, где оптимизация отключена.

Проблема возникает, когда я переключаюсь в режим выпуска, в котором включены оптимизации. Трассировка стека выглядит так:

> FindActionName at offset 66 in file:line:column <filename unknown>:0:0
> Email at offset 296 in file:line:column <filename unknown>:0:0
> CallingEmailFromRealControllerShouldFindMailersActionName at offset 184
     in file:line:column <filename unknown>:0:0
> _InvokeMethodFast at offset 0 in file:line:column <filename unknown>:0:0
> InvokeMethodFast at offset 152 in file:line:column <filename unknown>:0:0
...

Это берется из отказа unit test. В строке 3 этой трассы я должен увидеть метод под названием TestEmail, который определен в другом месте, но я считаю, что JITter вставляет его. Я прочитал, что вы можете предотвратить inlining, сделав метод виртуальным, но это не сработает. Кто-нибудь знает о надежном методе предотвращения внедрения метода, чтобы ваш метод обнаруживался в трассировке стека?

4b9b3361

Ответ 1

Вы можете использовать MethodImplAttribute и указать MethodImplOptions.NoInlining.

[MethodImpl(MethodImplOptions.NoInlining)]
void YourMethod()
{
    // do something
}

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

Ответ 2

Вы можете использовать дополнительные параметры, отмеченные System.Runtime.CompilerServices.CallerMemberNameAttribute, и это siblings CallerFilePath и CallerLineNumber. Если я правильно ее понимаю, это должно привести к правильному имени метода, независимо от того, в чем заключается то, что не указано. Вы получите только имя метода, но я не вижу ничего, чтобы получить имя класса/сборку и т.д.

Это должно быть само собой разумеющимся, но просто чтобы быть уверенным... что-то подобное не должно использоваться вне протоколов/диагностики.

Правильные способы сделать это, вероятно, будут следующими:

  • Передайте требуемую информацию в качестве параметра
  • Временно сохраните требуемую информацию в Thread.ExecutionContext при вызове функции

Я понимаю, что это, вероятно, не поможет Скотту все это время, но, возможно, кому-то это поможет.