Search code examples
c#linqexceptionexpression-trees

Unable to cast object of type 'System.Linq.Expressions.UnaryExpression' to type 'System.Linq.Expressions.MemberExpression'


I created a method in C# to get methodname

public string GetCorrectPropertyName<T>(Expression<Func<T, string>> expression)
{
   return ((MemberExpression)expression.Body).Member.Name; // Failure Point
}

and calling it as

string lcl_name = false;
public string Name
{
get { return lcl_name ; }
set 
    {
        lcl_name = value;
        OnPropertyChanged(GetCorrectPropertyName<ThisClassName>(x => x.Name));
}
}

This works fine if property is string and for all other types gives this exception:

Unable to cast object of type 'System.Linq.Expressions.UnaryExpression' to type 'System.Linq.Expressions.MemberExpression'.

  1. I changed string to object in method signature, but then it fails again.
  2. I changed calling from x => x.PropertyName to x => Convert.ToString(x.PropertyName) and it still fails

Where am I wrong?


Solution

  • You need a separate line to extract the Member where the input expression is a Unary Expression.

    Just converted this from VB.Net, so might be slightly off - let me know if I need to make any minor tweaks:

    public string GetCorrectPropertyName<T>(Expression<Func<T, Object>> expression)
    {
        if (expression.Body is MemberExpression) {
            return ((MemberExpression)expression.Body).Member.Name;
        }
        else {
            var op = ((UnaryExpression)expression.Body).Operand;
            return ((MemberExpression)op).Member.Name;
        }                
    }
    

    The VB version is:

    Public Shared Function GetCorrectPropertyName(Of T) _
                 (ByVal expression As Expression(Of Func(Of T, Object))) As String
        If TypeOf expression.Body Is MemberExpression Then
            Return DirectCast(expression.Body, MemberExpression).Member.Name
        Else
            Dim op = (CType(expression.Body, UnaryExpression).Operand)
            Return DirectCast(op, MemberExpression).Member.Name
        End If
    End Function
    

    Note that the input expression does not return string necessarily - that constrains you to only reading properties that return strings.