Вот документация для атрибута. Не упоминается, когда оно оценивается.
Вот документация по более широкому механизму CallerInformation. Он делает следующее утверждение:
Значения информации о вызывающем объекте передаются в виде литералов в промежуточный язык (IL) во время компиляции. В отличие от результатов свойства StackTrace для исключений, на результаты не влияет обфускация.
но не содержит никаких заявлений относительно времени, последовательности или явного встраивания.
Гарантированно ли установлен CallerMemberNameAttribute до того, как вызывающий абонент будет встроен?
Если нет, существует ли к настоящему времени более надежный механизм?
(На самом деле мне нужна подпись или, по крайней мере, имя текущей функции, но все инструкции по ее выполнению направлены на «вызов другой функции и использование CallerMemberNameAttribute» или на очевидные решения во время выполнения. Не в восторге от перспективы необходимости аннотировать каждого вызывающего объекта с помощью [MethodImpl(MethodImplOptions.NoInlining)]: Его легко пропустить в Code Review, и он вообще(?) не поддерживается инструментами рефакторинга.)
@Fildor: Вызов функций A => B => C. C имеет CallerMemberNameAttribute. B становится встроенным. Отладочный вывод: B; Вывод релиза: А. Проблема! В C++ я бы просто перешел к C в B: __func__.
Но в C# встраивание работает не так.
@Charlieface: Это мог быть ответ. Отсюда и тег языковой юрист. ... В настоящее время в единственном представленном ответе (пока?) немного мало ссылок, так что у вас еще есть шанс.





«Время компиляции», к сожалению, немного двусмысленно в C#, поскольку существует как компилятор C# -> IL, так и компилятор IL -> машинного кода (называемый компилятором «точно в срок» или jitter). Существует также компилятор Ahead of Time, но он, по сути, делает то же самое, что и джиттер, только «заранее».
Ваша цитата ясно дает понять, что информация о вызывающем абоненте генерируется как часть компиляции C# -> IL.
С другой стороны, за встраивание отвечает джиттер (или AOT). Так что да, он гарантированно будет оценен перед любой встраиванием.
Ну, если вы говорите, что это "проясняет"... - Не могу сказать, что для меня это прояснилось. Но в любом случае хорошие новости.
Я думаю, что Йонас имел в виду «значения информации о вызывающем абоненте передаются в промежуточный язык (IL) в виде литералов во время компиляции». (особенно жирная часть). И я должен согласиться, это довольно ясно.
@Fildor: Это помогает только тогда, когда вы знаете, не разрешено ли встраивание до указанного эмиттанса. Обратите внимание, что предложение не станет даже немного неправильным, если для вызова A => B => C, B были бы вставлены перед отправкой литерала в IL C. Произошло бы то же самое — только с неправильным значением (A вместо Б). Также обратите внимание: «В настоящее время ни один компилятор не делает этого таким образом». в основном полагается на неопределенное поведение и может измениться при любом незначительном увеличении версии указанного компилятора, если в спецификации нет гарантии.
@Zsar Я думаю, что документация просто предполагает некоторое знакомство с архитектурой .net. C# также довольно хорошо позволяет избежать «неопределённого поведения», см. цель проектирования «яма успеха».
Я принял другой ответ, так как он удовлетворил языкового юриста со специальной цитатой, но этот был первым и почти сразу же дал мне практический совет, что тоже приятно. Так что хотя бы +1.
Встраивание — это не то, что делает компилятор C#, оно происходит на более низком уровне в JIT (или AOT-компиляторе), поэтому компилятор C# всегда будет выдавать значение в обычных инструкциях ldstr и callvirt. В любом случае, встраивание никогда не должно иметь побочных эффектов, поэтому даже если бы оно было вставлено, это не должно было бы стать проблемой.
Вы можете доказать это с помощью простого теста, в котором используется MethodImpl.AggressiveInlining, посмотрите результаты и декомпиляцию.
Обратите также внимание на спецификацию, в которой говорится:
21.5.5.4 Атрибут
CallerMemberNameИспользование
System.Runtime.CompilerServices.CallerMemberNameAttributeдопускается в необязательных параметрах при наличии стандартного неявного преобразования (§10.4.2) из stringв тип параметра.Если вызов функции из места внутри тела члена функции или внутри атрибута, примененного к самому члену функции или ее возвращаемому типу, параметрам или параметрам типа в исходном коде, пропускает необязательный параметр с
CallerMemberNameAttribute, то строковый литерал, представляющий имя этого члена используется в качестве аргумента вызова вместо значения параметра по умолчанию.
Таким образом, в спецификации явно указано, что это значение должно использоваться в качестве параметра, встраивание не допускается.
Акцент может работать лучше, если его свести к просто «тому» или «тому члену», то есть, в отличие от моей исходной цитаты, он явно исключает любой другой член, который мог бы присутствовать, если бы этот шаг произошел после некоторой гипотетической трансформации. Эта формулировка должна требовать правильного определения значения и тем самым запрещать дальнейшее развитие событий в этом отношении (если не будет изменено, конечно, но нам придется где-то выбрать наши аксиомы), как это желательно.
Какую проблему вам нужно решить? Из всего этого текста я понимаю, что вам нужно имя — или, лучше, если возможно, полная подпись — текущего метода, не прибегая к отражению во время выполнения? Не могли бы вы привести пример кода, который пострадает от встраивания, как вы предполагали?