Lambda表达式' x =>x. property '更改为' x =>转换(x.Property)”

本文关键字:Property 转换 property 表达式 Lambda | 更新日期: 2023-09-27 18:17:22

我有一个示例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"; }
}

和一个扩展方法

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

我像这样使用

Data data = new Data();
data.Method(x => x.TestInt, x => x.TestBool, x => x.TestString);

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

properties[0] = x => Convert(x.TestId);
properties[1] = x => Convert(x.TestBool);
properties[2] = x => x.TestString;

可以看到,TestString部分没有变化。我试着把我的属性改成params Expression<Func<T, bool>>[]params Expression<Func<T, int>>[],只传递相应的参数,它工作得很好。我明白这个问题来自于转换成object,但我不能弄清楚。

Lambda表达式' x =>x. property '更改为' x =>转换(x.Property)”

由于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
在一天结束时,常规c#编译器实现了一些技巧来强制转换值类型以适应object(引用类型)。也许这个问题&A"ValueTypes如何从Object (ReferenceType)派生而仍然是ValueTypes?"Eric Lippert回答的问题对你来说可能很有趣。

OP说…

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

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

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

Method中,您可以通过NodeType = Convert获得UnaryExpression。如果是,只需检查该表达式的Operand属性。

我不确定你想要实现什么,但这里有一种方法来避免这些转换。问题是,您正在转换为object,这只会因为您声明Expression变量/参数的方式而发生。

当你说:

Expression<Func<int>> f1 = () => 1234;

不能转换。所以这样做:

Expression<Func<int>> f1 = () => 1234;
Expression<Func<string>> f2 = () => "x";
LambdaExpression[] myFunctionExpressions = new LambdaExpression[] { f1, f2 };
Method(myFunctionExpressions);

myFunctionExpressions的参数也必须是LambdaExpression[]

调用者现在变得更啰嗦了,但是树是干净的。