web-dev-qa-db-fra.com

Impossible de convertir un objet de type 'System.Linq.Expressions.UnaryExpression' en type 'System.Linq.Expressions.MemberExpression'

J'ai créé une méthode en C # pour obtenir le nom de la méthode

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

et l'appeler comme

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

Cela fonctionne bien si la propriété est une chaîne et pour tous les autres types donne cette exception:

Impossible de convertir un objet de type "System.Linq.Expressions.UnaryExpression" en type "System.Linq.Expressions.MemberExpression".

  1. J'ai changé la chaîne en objet dans la signature de la méthode, mais cela échoue à nouveau.
  2. J'ai changé l'appel de x => x.PropertyName En x => Convert.ToString(x.PropertyName) et il échoue toujours

Où ai-je tort?

35
Nikhil Agrawal

Vous avez besoin d'une ligne distincte pour extraire le membre où l'expression d'entrée est une expression unaire.

Je viens de convertir cela à partir de VB.Net, donc cela pourrait être légèrement désactivé - faites-moi savoir si j'ai besoin de faire des ajustements mineurs:

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;
    }                
}

La version VB est:

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

Notez que l'expression d'entrée ne renvoie pas nécessairement de chaîne - cela vous oblige à lire uniquement les propriétés qui renvoient des chaînes.

57
Jon Egerton

C'est apparemment lié à la boxe/unboxing. Les expressions lambda renvoyant des types de valeur qui nécessitent une boxe seront représentées comme UnaryExpressions tandis que celles qui renvoient des types de référence seront représentées comme MemberExpressions.

9
Scott Munro

Après avoir posé cette question (oui je suis OP), j'ai reçu des commentaires sur la question de Jon

et je suis venu avec cette

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;
}
}
4
Nikhil Agrawal