无法将“System.Linq.Expressions.UnaryExpression”类型的对象转换为“System.Linq.Expressions.MemberExpression”类型

Posted

技术标签:

【中文标题】无法将“System.Linq.Expressions.UnaryExpression”类型的对象转换为“System.Linq.Expressions.MemberExpression”类型【英文标题】:Unable to cast object of type 'System.Linq.Expressions.UnaryExpression' to type 'System.Linq.Expressions.MemberExpression' 【发布时间】:2012-09-14 08:09:06 【问题描述】:

我创建了一个method in C# 来获取方法名

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


如果属性是字符串并且所有其他类型都给出此异常,则此方法工作正常:

    我在方法签名中将字符串更改为对象,但随后又失败了。 我将呼叫从 x =&gt; x.PropertyName 更改为 x =&gt; Convert.ToString(x.PropertyName),但仍然失败

我哪里错了?

【问题讨论】:

IMO 最好使用它的变体,其中助手采用Expression&lt;Func&lt;T&gt;&gt;。这会将调用站点语法更改为 GetCorrectPropertyName(() =&gt; this.Name),在我看来,这既更便于键入(无需提供泛型类型参数),也更易于阅读(this.Name 非常好地传达了意图)。 @Jon:好友随时添加您的答案。如果比目前的答案更好,我肯定会接受你的。 我不想这样做,因为它会篡夺您的问题的意图。但是您可以轻松地从here 获取它的代码,Microsoft 正是在 Prism 中做到了这一点。 没有什么可以阻止您在 Prism 2 中执行此操作(或者完全在 Prism 之外)。 @Jon:但是(棱镜的)方法不是仅限于属性还是也可以应用于方法? 【参考方案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

请注意,输入表达式不一定返回字符串 - 这会限制您仅读取返回字符串的属性。

【讨论】:

有人想知道为什么这样的东西还没有包含在 BCL 或扩展中。它非常有用。 只是想知道如何为属性和方法(VB.Net 的 Sub 和 Function)使用/调用它? @NikhilAgrawal:你最好提出一个新问题,参考这个问题,并充分解释你的要求。 我想要一个扩展方法,它将返回属性或方法的名称(VB.Net 的子和函数)该属性/方法可以或不能与调用它的位置相同。 这很有用!谢谢!【参考方案2】:

这是与装箱/拆箱相关的apparently。返回需要装箱的值类型的 Lambda 表达式将表示为 UnaryExpressions,而返回引用类型的将表示为 MemberExpressions。

【讨论】:

这详细说明了评分最高的答案,并为那些对答案不满意的人提供了进一步的见解。【参考方案3】:

在问完这个问题(是的,我是 OP)后,我收到了来自 Jon 的 cmets 问题

我想出了这个

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】:

上述答案的现代版本。

private static string GetPropertyName<T>(Expression<Func<T, object>> expression) 
=> expression.Body switch

    MemberExpression expr => expr.Member.Name,
    UnaryExpression expr => ((MemberExpression)expr.Operand).Member.Name,
    _ => throw new ArgumentException($"Argument nameof(expression) is not a property expression.", nameof(expression)),
;

【讨论】:

以上是关于无法将“System.Linq.Expressions.UnaryExpression”类型的对象转换为“System.Linq.Expressions.MemberExpression”类型的主要内容,如果未能解决你的问题,请参考以下文章

无法将 createdAt 和 updatedAt 保存为日期时间值,也无法将后端保存为前端

C# 无法将类型为“System.Byte[]”的对象强制转换为类型“System.Data.DataTable

无法将类型为“System.Collections.Generic.List`1[EPMS.Domain.SingleItem]”的对象强制转换为类型“EPMS

无法将 .json 文件从 CSV 下载到 JSON 转换并且无法将 JSON 转换为 CSV

无法将 ReactiveUI 添加到 NUnit 测试项目

“无法将图像数据写入路径” - Laravel 图像干预