Предотвращение встраивания JIT по методу - PullRequest
27 голосов
/ 02 марта 2011

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

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

> 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
...

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

Ответы [ 2 ]

35 голосов
/ 02 марта 2011

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

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

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

5 голосов
/ 11 января 2013

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

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

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

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

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

...