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
,但我不能弄清楚。
由于Int32
和Boolean
都不是引用类型,因此整个表达式树需要显式地将它们转换为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[]
调用者现在变得更啰嗦了,但是树是干净的。