Гарантируется ли оценка CallerMemberNameAttribute перед встраиванием?

Вот документация для атрибута. Не упоминается, когда оно оценивается.

Вот документация по более широкому механизму CallerInformation. Он делает следующее утверждение:

Значения информации о вызывающем объекте передаются в виде литералов в промежуточный язык (IL) во время компиляции. В отличие от результатов свойства StackTrace для исключений, на результаты не влияет обфускация.

но не содержит никаких заявлений относительно времени, последовательности или явного встраивания.

Гарантированно ли установлен CallerMemberNameAttribute до того, как вызывающий абонент будет встроен?

Если нет, существует ли к настоящему времени более надежный механизм?

(На самом деле мне нужна подпись или, по крайней мере, имя текущей функции, но все инструкции по ее выполнению направлены на «вызов другой функции и использование CallerMemberNameAttribute» или на очевидные решения во время выполнения. Не в восторге от перспективы необходимости аннотировать каждого вызывающего объекта с помощью [MethodImpl(MethodImplOptions.NoInlining)]: Его легко пропустить в Code Review, и он вообще(?) не поддерживается инструментами рефакторинга.)

Какую проблему вам нужно решить? Из всего этого текста я понимаю, что вам нужно имя — или, лучше, если возможно, полная подпись — текущего метода, не прибегая к отражению во время выполнения? Не могли бы вы привести пример кода, который пострадает от встраивания, как вы предполагали?

Fildor 14.06.2024 13:47

@Fildor: Вызов функций A => B => C. C имеет CallerMemberNameAttribute. B становится встроенным. Отладочный вывод: B; Вывод релиза: А. Проблема! В C++ я бы просто перешел к C в B: __func__.

Zsar 14.06.2024 14:20

Но в C# встраивание работает не так.

Charlieface 14.06.2024 14:24

@Charlieface: Это мог быть ответ. Отсюда и тег языковой юрист. ... В настоящее время в единственном представленном ответе (пока?) немного мало ссылок, так что у вас еще есть шанс.

Zsar 14.06.2024 14:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

«Время компиляции», к сожалению, немного двусмысленно в C#, поскольку существует как компилятор C# -> IL, так и компилятор IL -> машинного кода (называемый компилятором «точно в срок» или jitter). Существует также компилятор Ahead of Time, но он, по сути, делает то же самое, что и джиттер, только «заранее».

Ваша цитата ясно дает понять, что информация о вызывающем абоненте генерируется как часть компиляции C# -> IL.

С другой стороны, за встраивание отвечает джиттер (или AOT). Так что да, он гарантированно будет оценен перед любой встраиванием.

Ну, если вы говорите, что это "проясняет"... - Не могу сказать, что для меня это прояснилось. Но в любом случае хорошие новости.

Zsar 14.06.2024 14:08

Я думаю, что Йонас имел в виду «значения информации о вызывающем абоненте передаются в промежуточный язык (IL) в виде литералов во время компиляции». (особенно жирная часть). И я должен согласиться, это довольно ясно.

Fildor 14.06.2024 14:33

@Fildor: Это помогает только тогда, когда вы знаете, не разрешено ли встраивание до указанного эмиттанса. Обратите внимание, что предложение не станет даже немного неправильным, если для вызова A => B => C, B были бы вставлены перед отправкой литерала в IL C. Произошло бы то же самое — только с неправильным значением (A вместо Б). Также обратите внимание: «В настоящее время ни один компилятор не делает этого таким образом». в основном полагается на неопределенное поведение и может измениться при любом незначительном увеличении версии указанного компилятора, если в спецификации нет гарантии.

Zsar 14.06.2024 14:37

@Zsar Я думаю, что документация просто предполагает некоторое знакомство с архитектурой .net. C# также довольно хорошо позволяет избежать «неопределённого поведения», см. цель проектирования «яма успеха».

JonasH 14.06.2024 15:01

Я принял другой ответ, так как он удовлетворил языкового юриста со специальной цитатой, но этот был первым и почти сразу же дал мне практический совет, что тоже приятно. Так что хотя бы +1.

Zsar 25.06.2024 19:42
Ответ принят как подходящий

Встраивание — это не то, что делает компилятор C#, оно происходит на более низком уровне в JIT (или AOT-компиляторе), поэтому компилятор C# всегда будет выдавать значение в обычных инструкциях ldstr и callvirt. В любом случае, встраивание никогда не должно иметь побочных эффектов, поэтому даже если бы оно было вставлено, это не должно было бы стать проблемой.

Вы можете доказать это с помощью простого теста, в котором используется MethodImpl.AggressiveInlining, посмотрите результаты и декомпиляцию.

Обратите также внимание на спецификацию, в которой говорится:

21.5.5.4 Атрибут CallerMemberName

Использование System.Runtime.CompilerServices.CallerMemberNameAttribute допускается в необязательных параметрах при наличии стандартного неявного преобразования (§10.4.2) из ​​string в тип параметра.

Если вызов функции из места внутри тела члена функции или внутри атрибута, примененного к самому члену функции или ее возвращаемому типу, параметрам или параметрам типа в исходном коде, пропускает необязательный параметр с CallerMemberNameAttribute, то строковый литерал, представляющий имя этого члена используется в качестве аргумента вызова вместо значения параметра по умолчанию.

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

Акцент может работать лучше, если его свести к просто «тому» или «тому члену», то есть, в отличие от моей исходной цитаты, он явно исключает любой другой член, который мог бы присутствовать, если бы этот шаг произошел после некоторой гипотетической трансформации. Эта формулировка должна требовать правильного определения значения и тем самым запрещать дальнейшее развитие событий в этом отношении (если не будет изменено, конечно, но нам придется где-то выбрать наши аксиомы), как это желательно.

Zsar 14.06.2024 16:19

Другие вопросы по теме