无法将“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 => x.PropertyName
更改为 x => Convert.ToString(x.PropertyName)
,但仍然失败
我哪里错了?
【问题讨论】:
IMO 最好使用它的变体,其中助手采用Expression<Func<T>>
。这会将调用站点语法更改为 GetCorrectPropertyName(() => 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