c# - 为什么将表达式对象传递给 where 会返回与输入 lambda 表达式不同的结果?
问题描述
我有以下代码正确返回六个对象的列表
var items = db.items.take(100);
var result = items.Where(m => m.Cost.ToString().ToLower().Contains("67.5")).ToList(); //returns 6 items
我正在尝试使用动态表达式做同样的事情。
// Print out the expression.
// .ToString() returns "m => m.Cost.ToString().ToLower().Contains("67.5")"
var whereClause = ContainsPredicate<item>("Cost", "67.5");
var result = items.Where(whereClause).ToList(); //returns 0 items
当我尝试使用 sql profiler 查看发送到数据库的内容时,我注意到它删除了我的子句并添加了WHERE 0 = 1
ContainsPredicate 方法实现:
public static Expression<Func<T, bool>> ContainsPredicate<T>(string memberName, string searchValue)
{
var parameter = Expression.Parameter(typeof(T), "m");
var member = Expression.PropertyOrField(parameter, memberName);
MethodCallExpression memberToString = Expression.Call(Expression.Constant(member), member.GetType().GetMethod("ToString", Type.EmptyTypes));
MethodCallExpression memberToLower = Expression.Call(memberToString,"ToLower", null);
var body = Expression.Call(memberToLower,"Contains",Type.EmptyTypes,Expression.Constant(searchValue));
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
任何建议表示赞赏。谢谢。
解决方案
public static void Test()
{
var myItem = new Item() { Cost = 67.5 };
var items = new List<Item> { myItem };
var result = items.Where(m =>
m.Cost.ToString().ToLower().
Contains("67,5")).ToList();
var whereClause = ContainsPredicate<Item>("Cost", "67,5");
// var test1 = whereClause(myItem);
var result2 = items.Where(whereClause).ToList(); // returns 1 result in my case
}
public static Func<T, bool> ContainsPredicate<T>(string memberName, string searchValue)
{
var parameter = Expression.Parameter(typeof(T), "m");
var member = Expression.PropertyOrField(parameter, memberName);
// Mistake was here:
var doubleToStr = member.Type.GetMethod("ToString", Type.EmptyTypes);
MethodCallExpression memberToString = Expression.Call(member, doubleToStr);
MethodCallExpression memberToLower =
Expression.Call(memberToString, "ToLower", null);
var body = Expression.Call(memberToLower, "Contains", Type.EmptyTypes
, Expression.Constant(searchValue));
var lamb = Expression.Lambda<Func<T, bool>>(body, parameter);
// we need to compile
return lamb.Compile();
}
我做的第一件事只是编译memberToLower
并返回字符串“m.cost”而不是你的双精度。“m.cost”显然永远不会包含“67.5”。所以你去。
你确定你不想要这样的东西:
public static Func<T, bool> ContainsPredicate2<T>(string memberName, string searchValue)
{
var prop = typeof(T).GetProperty(memberName);
Func<T, bool> func = (T obj2) =>
prop.GetValue(obj2).ToString().ToLower().Contains(searchValue);
return func;
}
推荐阅读
- c++ - Clang 不会内联 std::atomic::load 来加载 64 位结构
- javascript - React Cytoscape JS:所有节点都累积在一个位置
- python - Python confluent_kafka:消费(0)无法触发回调
- python - 树莓派如何通过 IFTTT 接收来自 webhook 的触发事件?
- android - 约束视图问题
- python - 如何在python中使用函数和循环调用变量
- javascript - 如何将 API JSON 响应参数传递给材质 ui 表
- google-app-engine - 使用 requirements.txt 的 Google App Engine 标准 Python 3 上的 Ta-lib 包
- r - 如何添加缺失的美学:标签到 geom_label()
- sql-server - 如果值增加 > 5,则创建警报 - SQL Server