Update: This is no longer an issue from C# 6, which has introduced the
nameof
operator to address such scenarios (see MSDN).Note: Refer to “Getting names of local variables (and parameters) at run-time through lambda expressions” for a generalization of this question, as well as some answers.
I like the idea of using lambda expressions to create refactor-safe implementations of the INotifyPropertyChanged
interface, using code similar to that provided by Eric De Carufel.
I’m experimenting with implementing something similar for providing the parameter name to an ArgumentException
(or its derived classes) in a refactor-safe manner.
I have defined the following utility method for performing null
checks:
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);
}
}
Argument validation may then be performed in a refactor-safe manner using the following syntax:
CheckNotNull(() => arg); // most concise
CheckNotNull(arg, () => args); // equivalent, but more efficient
My concern lies in the following lines:
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
A MemberExpression
represents “accessing a field or property”. It is guaranteed to work correctly in the INotifyPropertyChanged
case, since the lambda expression would be a property access.
However, in my code above, the lambda expression is semantically a parameter access, not a field or property access. The only reason the code works is that the C# compiler promotes any local variables (and parameters) that are captured in anonymous functions to instance variables within a compiler-generated class behind the scenes. This is corroborated by Jon Skeet.
My question is: Is this behaviour (of promoting captured parameters to instance variables) documented within the .NET specification, or is it just an implementation detail that may change in alternate implementations or future releases of the framework? Specifically, may there be environments where parameterAccessExpression.Body is MemberExpression
returns false
?