我有一个示例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
,但我无法弄清楚。
答案 0 :(得分:4)
由于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#编译器会实现一些 trickery 来转换值类型以适合object
(引用类型)。也许这个Q&amp; A“How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?”Eric Lippert回答它可能对你很有意思。
是否有任何方法可以强制表达保持不受影响?
没有。您应该处理这两种情况:使用和不使用强制转换来访问属性。
答案 1 :(得分:3)
如果要分析原始表达式,一种可能的方法是手动删除Convert
表达式。
在Method
中,您可能会获得UnaryExpression
with NodeType
= Convert
。如果是这样,只需检查此表达式的Operand属性。
答案 2 :(得分:1)
我不确定你想要实现什么,但这是一种不进行这些转换的方法。问题是您正在转换为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[]
。
呼叫者现在变得更加冗长,但树木很干净。