Unable to cast object of type 'System.Linq.Exp

2019-01-17 09:54发布

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?

3条回答
时光不老,我们不散
2楼-- · 2019-01-17 10:22

After asking this question(yes I am OP) i received comments on question from Jon

and I came up with this

public string ResolvePropertyName<TEntity>(Expression<Func<TEntity>> expression)
{
try {
    if (expression == null) {
        Throw New ArgumentNullException("propertyExpression")
    }

    object memberExpression = expression.Body as MemberExpression;
    if (memberExpression == null) {
        Throw New ArgumentException("The expression is not a member access expression.", "propertyExpression")
    }

    object property = memberExpression.Member as PropertyInfo;
    if (property == null) {
        Throw New ArgumentException("The member access expression does not access a property.", "propertyExpression")
    }

    object getMethod = property.GetGetMethod(true);
    if (getMethod.IsStatic) {
        Throw New ArgumentException("The referenced property is a static property.", "propertyExpression")
    }
    return memberExpression.Member.Name;
} catch (Exception ex) {
    return string.Empty;
}
}
查看更多
Deceive 欺骗
3楼-- · 2019-01-17 10:42

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.

查看更多
劫难
4楼-- · 2019-01-17 10:46

This is apparently related to boxing/unboxing. Lambda expressions returning value types that require boxing will be represented as UnaryExpressions whereas those that return reference types will be represented as MemberExpressions.

查看更多
登录 后发表回答