Обновление. Это больше не проблема с С# 6, которая внедрила оператор
nameof
для решения таких сценариев (см. MSDN).Примечание. Обратитесь к разделу Получение имен локальных переменных (и параметров) во время выполнения через лямбда-выражения" для обобщения этот вопрос, а также некоторые ответы.
Мне нравится идея использования лямбда-выражений для создания рефакторизуемых реализаций интерфейса INotifyPropertyChanged
, используя код, аналогичный тому, который предоставляется Eric De Carufel.
Im экспериментирует с реализацией чего-то подобного для предоставления имени параметра ArgumentException
(или его производных классов) в режиме рефакторинга.
Я определил следующий метод утилиты для выполнения проверок null
:
public static void CheckNotNull<T>(Expression<Func<T>> parameterAccessExpression)
{
Func<T> parameterAccess = parameterAccessExpression.Compile();
T parameterValue = parameterAccess();
CheckNotNull(parameterValue, parameterAccessExpression);
}
public static void CheckNotNull<T>(T parameterValue,
Expression<Func<T>> parameterAccessExpression)
{
if (parameterValue == null)
{
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
string parameterName = memberExpression.Member.Name;
throw new ArgumentNullException(parameterName);
}
}
Проверка правильности аргумента может быть выполнена в режиме рефакторинга с использованием следующего синтаксиса:
CheckNotNull(() => arg); // most concise
CheckNotNull(arg, () => args); // equivalent, but more efficient
Моя забота заключается в следующих строках:
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
A MemberExpression
представляет "доступ к полю или свойству". Он гарантированно работает корректно в случае INotifyPropertyChanged
, поскольку выражение лямбда будет доступностью свойств.
Однако в моем коде выше выражение лямбда семантически относится к параметру, а не к доступу к полю или свойствам. Единственная причина, по которой работает код, заключается в том, что компилятор С# продвигает любые локальные переменные (и параметры), которые фиксируются в анонимных функциях для переменных экземпляра в классе, создаваемом компилятором, за кулисами. Это подтверждается Jon Skeet.
Мой вопрос: Является ли это поведение (продвижение захваченных параметров в переменные экземпляра) документированным в спецификации .NET, или это просто деталь реализации, которая может измениться в альтернативных реализациях или будущих версиях структуры? В частности, могут быть среды, в которых parameterAccessExpression.Body is MemberExpression
возвращает false
?