Подтвердить что ты не робот

Невозможно передать объект типа "System.Linq.Expressions.UnaryExpression" для ввода "System.Linq.Expressions.MemberExpression"

Я создал метод в С#, чтобы получить имя метода

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

и называя его

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

Это отлично работает, если свойство является строкой, и для всех остальных типов это исключение:

Невозможно передать объект типа "System.Linq.Expressions.UnaryExpression" для ввода "System.Linq.Expressions.MemberExpression".

  • Я изменил строку на объект в сигнатуре метода, но потом снова сработал.
  • Я изменил вызов с x => x.PropertyName на x => Convert.ToString(x.PropertyName), и он все еще не работает

Где я ошибаюсь?

4b9b3361

Ответ 1

Вам нужна отдельная строка для извлечения члена, где входное выражение является Унарным выражением.

Просто изменил это из VB.Net, так что может быть немного отключен - сообщите мне, нужно ли мне делать какие-либо незначительные изменения:

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

Версия VB:

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

Обратите внимание, что входное выражение не возвращает строку обязательно - это ограничивает только чтение свойств, возвращающих строки.

Ответ 2

Это очевидно, связанный с боксом/распаковкой. Лямбда-выражения, возвращающие типы значений, которые требуют бокса, будут представлены как UnaryExpressions, тогда как те, которые возвращают ссылочные типы, будут представлены как MemberExpressions.

Ответ 3

После того, как я задал этот вопрос (да, я ОП), я получил комментарии по вопросу от Jon

и я придумал этот

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