Lambda Expression`x => x.Property`变为`x => Convert(x.Property)`

Art*_*Rey 7 c# lambda object

我有一个样本Data

public class Data
{
    public int TestInt { get; set; }
    public bool TestBool { get; set; }
    public string TestString { get; set; }

    public Data() { TestInt = 10; TestBool = true; TestString = "test"; }
}
Run Code Online (Sandbox Code Playgroud)

并且是一种扩展方法

public static void Method<T>(this T item, params Expression<Func<T, object>>[] properties)
{
    /* Some stuff */   
}
Run Code Online (Sandbox Code Playgroud)

我这样用

Data data = new Data();
data.Method(x => x.TestInt, x => x.TestBool, x => x.TestString);
Run Code Online (Sandbox Code Playgroud)

Method<T>确实收到3个属性,但它稍微改为:

properties[0] = x => Convert(x.TestId);
properties[1] = x => Convert(x.TestBool);
properties[2] = x => x.TestString;
Run Code Online (Sandbox Code Playgroud)

如您所见,该TestString部分没有变化.我尝试将我的属性更改为params Expression<Func<T, bool>>[]params Expression<Func<T, int>>[]只传递相应的参数,它工作正常.我知道这个问题来自转换成一个object但我无法弄明白.

Mat*_*zer 5

由于Int32Boolean都不是引用类型,因此整个表达式树需要将它们显式转换为object.

在使用常规 C# 编译器进行编译时,有一些隐式操作可用,而其他一些则在实现表达式树时需要显式操作。

你想测试自己这个事实吗?

public struct A {}
public class B { }

public class C
{
     public A A { get; set; }
     public B B { get; set; }
}

C c = new C();
Expression<Func<C, object>> expr1 = some => some.A; // Convert(some.A)
Expression<Func<C, object>> expr2 = some => some.B; // some.B
Run Code Online (Sandbox Code Playgroud)

归根结底,常规 C# 编译器实现了一些技巧来转换值类型以适应object(引用类型)。也许这个问答“ ValueTypes 如何从 Object (ReferenceType) 派生并仍然是 ValueTypes? ” Eric Lippert 的回答可能对您很有趣。

OP说...

没有办法强制表达式保持不变吗?

不。您应该处理两种情况:使用和不使用强制转换访问属性。


qxg*_*qxg 3

如果您想分析原始表达,一种可能的方法是手动删除Convert表达。

在 中Method,您可能会得到UnaryExpression一个NodeType=Convert。如果是这样,只需检查该表达式的 Operand 属性。

  • 这正是我一直在寻找的。通过执行 `(property.Body.NodeType == ExpressionType.Convert ? (property.Body as UnaryExpression).Operand : property.Body) as MemberExpression;` 解决了这个问题 (3认同)