从 IQueryable<T> 谓词得到 Func<T, bool>
Get from IQueryable<T> predicate Func<T, bool>
我正在尝试将查询从一个集合应用到另一个集合。
我的测试样本:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Expression sourceExpression = Amazings().Where(x => x.Name.Equals("Kasa")).AsQueryable().Expression;
Expression<Func<Amazing, bool>> predicate = Expression.Lambda<Func<Amazing, bool>>(sourceExpression, Expression.Parameter(typeof(Amazing)));
var col2 = Amazings().Where(predicate.Compile());
}
private IEnumerable<Amazing> Amazings()
{
var amazings = new List<Amazing>
{
new Amazing
{
Name = "Kasa",
},
new Amazing
{
Name = "Ma@p2a"
}
};
return amazings;
}
class Amazing
{
public string Name { get; set; }
}
}
怎么了?
当我在调试中 运行 这个测试时,我得到了异常:
您不能对 return 类型“System.Boolean”使用“System.Linq.EnumerableQuery`1[UnitTestProject1.UnitTest1+Amazing]”等表达式。
如果我运行这个没有参数我得到异常我没有参数。
如果我将参数更改为 boolean 类型,我会遇到异常:您不能将元素 bool 类型用于委托参数类型 Amazing...
我测试了几个选项,但没有任何效果。
我还发现密钥可以通过将 Expression 强制转换为:MethodCallExpression 但它不是,或者我不知道如何。
我试过这样的东西:
MethodCallExpression e = query.Expression as MethodCallExpression;
MemberExpression memberExpression = (MemberExpression)e.Object;
Expression<Func<Amazing, bool>> getCallerExpression = Expression<Func<Amazing>>.Lambda<Func<Amazing, bool>>(memberExpression);
很遗憾,memberExpression 为空。
我在网上搜索了一下,唯一找到的是提示:~"don't do this".
我怎样才能实现我的目标?
由于您调用的是 Enumerable.Where
而不是 Queryable.Where
,因此您拥有的 lambda 从未被翻译成 Expression
,它只会被编译成一个方法,而 IQueryable
你甚至没有任何办法到达那个代表,因为 它 看到的只是一个任意的 IEnumerable<T>
.
不清楚您想做什么...但是正如 Servy 所写,您将 AsQueryable()
放在了错误的位置。正确的地方是 before the .Where()
,这是一个单元测试,我建议 returns 数据的方法应该直接 return IQueryable<T>
,以更好地模拟您可以在代码中找到的 "normal" 查询。
试试看看这是不是你想要的...
public void TestMethod1()
{
var q1 = Amazings().Where(x => x.Name.Equals("Kasa"));
Expression predicate = q1.Expression;
var q2 = Amazings();
IQueryable<Amazing> q3 = q2.Provider.CreateQuery<Amazing>(predicate);
}
private IQueryable<Amazing> Amazings()
{
var amazings = new List<Amazing>
{
new Amazing
{
Name = "Kasa",
},
new Amazing
{
Name = "Ma@p2a"
}
};
return amazings.AsQueryable();
}
请注意,在大多数情况下,您不能简单地移动 .Where()
的 Expression<Func<Amazing, bool>>
条件,因为您可能有 .Where().Select()
或类似的东西。
其他可能的解决方案,如果您知道最后一个方法是 .Where()
并且您 真的 想要 "move" Expression<Func<Amazing, bool>>
:
MethodCallExpression mce = predicate as MethodCallExpression;
if (mce == null)
{
throw new Exception();
}
UnaryExpression quote = mce.Arguments[1] as UnaryExpression;
if (quote == null || quote.NodeType != ExpressionType.Quote)
{
throw new Exception();
}
Expression<Func<Amazing, bool>> lambda = quote.Operand as Expression<Func<Amazing, bool>>;
if (lambda == null)
{
throw new Exception();
}
IQueryable<Amazing> q4 = Amazings().Where(lambda);
我正在尝试将查询从一个集合应用到另一个集合。 我的测试样本:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Expression sourceExpression = Amazings().Where(x => x.Name.Equals("Kasa")).AsQueryable().Expression;
Expression<Func<Amazing, bool>> predicate = Expression.Lambda<Func<Amazing, bool>>(sourceExpression, Expression.Parameter(typeof(Amazing)));
var col2 = Amazings().Where(predicate.Compile());
}
private IEnumerable<Amazing> Amazings()
{
var amazings = new List<Amazing>
{
new Amazing
{
Name = "Kasa",
},
new Amazing
{
Name = "Ma@p2a"
}
};
return amazings;
}
class Amazing
{
public string Name { get; set; }
}
}
怎么了? 当我在调试中 运行 这个测试时,我得到了异常:
您不能对 return 类型“System.Boolean”使用“System.Linq.EnumerableQuery`1[UnitTestProject1.UnitTest1+Amazing]”等表达式。
如果我运行这个没有参数我得到异常我没有参数。
如果我将参数更改为 boolean 类型,我会遇到异常:您不能将元素 bool 类型用于委托参数类型 Amazing...
我测试了几个选项,但没有任何效果。
我还发现密钥可以通过将 Expression 强制转换为:MethodCallExpression 但它不是,或者我不知道如何。
我试过这样的东西:
MethodCallExpression e = query.Expression as MethodCallExpression;
MemberExpression memberExpression = (MemberExpression)e.Object;
Expression<Func<Amazing, bool>> getCallerExpression = Expression<Func<Amazing>>.Lambda<Func<Amazing, bool>>(memberExpression);
很遗憾,memberExpression 为空。
我在网上搜索了一下,唯一找到的是提示:~"don't do this".
我怎样才能实现我的目标?
由于您调用的是 Enumerable.Where
而不是 Queryable.Where
,因此您拥有的 lambda 从未被翻译成 Expression
,它只会被编译成一个方法,而 IQueryable
你甚至没有任何办法到达那个代表,因为 它 看到的只是一个任意的 IEnumerable<T>
.
不清楚您想做什么...但是正如 Servy 所写,您将 AsQueryable()
放在了错误的位置。正确的地方是 before the .Where()
,这是一个单元测试,我建议 returns 数据的方法应该直接 return IQueryable<T>
,以更好地模拟您可以在代码中找到的 "normal" 查询。
试试看看这是不是你想要的...
public void TestMethod1()
{
var q1 = Amazings().Where(x => x.Name.Equals("Kasa"));
Expression predicate = q1.Expression;
var q2 = Amazings();
IQueryable<Amazing> q3 = q2.Provider.CreateQuery<Amazing>(predicate);
}
private IQueryable<Amazing> Amazings()
{
var amazings = new List<Amazing>
{
new Amazing
{
Name = "Kasa",
},
new Amazing
{
Name = "Ma@p2a"
}
};
return amazings.AsQueryable();
}
请注意,在大多数情况下,您不能简单地移动 .Where()
的 Expression<Func<Amazing, bool>>
条件,因为您可能有 .Where().Select()
或类似的东西。
其他可能的解决方案,如果您知道最后一个方法是 .Where()
并且您 真的 想要 "move" Expression<Func<Amazing, bool>>
:
MethodCallExpression mce = predicate as MethodCallExpression;
if (mce == null)
{
throw new Exception();
}
UnaryExpression quote = mce.Arguments[1] as UnaryExpression;
if (quote == null || quote.NodeType != ExpressionType.Quote)
{
throw new Exception();
}
Expression<Func<Amazing, bool>> lambda = quote.Operand as Expression<Func<Amazing, bool>>;
if (lambda == null)
{
throw new Exception();
}
IQueryable<Amazing> q4 = Amazings().Where(lambda);