我有这个功能:
public List<T> Find(Expression<Func<T, bool>> query)
{
}
Find(x => x.Id == 4);
在方法内部
Find
我想链接And
条件。
像这样的东西:
query.And(x => x.Secured == false);//Secured is a memeber inside T like Id.
您的问题是您想在通用方法中访问
T
的成员。此时 T
可以是任何内容,因此编译器不会让您访问 Secured
,因为 T
可能没有 Secured
成员。
您可以将
T
转换为 dynamic
,但这只会将编译时错误更改为运行时错误(而且这很可怕)。
最好的方法是确保
T
实现一些具有 Secured 成员的已知接口。
public List<T> Find(Expression<Func<T, bool>> query) where T : ISecured
必须“打开”并重建表达式,如下所示:
public List<T> Find<T>(Expression<Func<T, bool>> query)
{
ParameterExpression parameter = query.Parameters[0];
Expression body = query.Body;
MemberExpression property = Expression.Property(parameter, "Secured");
body = Expression.AndAlso(body, Expression.Not(property));
Expression<Func<T, bool>> query2 = Expression.Lambda<Func<T, bool>>(body, parameter);
// Now you can use query2
return null;
}
请注意,我认为
x.Secured == false
等同于 !x.Secured
。显然 Secured
可能是一个奇怪的类,它会重载 ==
运算符,但我会忽略这种情况。
正如@Ralf 所建议的,你甚至可以简单地做两个
.Where
。喜欢:
public List<T> Find<T>(Expression<Func<T, bool>> query)
{
ParameterExpression parameter = query.Parameters[0];
MemberExpression property = Expression.Property(parameter, "Secured");
Expression<Func<T, bool>> query2 = Expression.Lambda<Func<T, bool>>(Expression.Not(property), parameter);
return context.Set<T>
.Where(query)
.Where(query2)
.ToList();
}
(我使用
context.Set<T>
作为示例,这与使用实体框架时所做的非常相似,但一般来说,几乎所有 IQuerable<>
/IEnumerable<>
将两个 .Where()
视为单个.Where()
具有 &&
条件)
我有和你类似的需求,最终创建了这个扩展:
public static class LinqExpressionExtensions
{
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
if (first == null ) return second;
if (second == null ) return first;
var invokedExpr = Expression.Invoke(second, first.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.And(first.Body, invokedExpr), first.Parameters);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
if (first == null ) return second;
if (second == null ) return first;
var invokedExpr = Expression.Invoke(second, first.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.Or(first.Body, invokedExpr), first.Parameters);
}
}
示例:
System.Linq.Expressions.Expression<Func<MyEntity, bool>> result = null;
System.Linq.Expressions.Expression<Func<MyEntity, bool>> CategoryExpression = null;
if (condition)
{
CategoryExpression = w => w.Id== 1;
}
else
{
CategoryExpression = w => w.Id== 2;
}
if (condition2)
{
Expression<Func<MyEntity, bool>> jointExpression = null;
jointExpression = w => w.JointId== 3;
result = CategoryExpression.Or(jointExpression);
}
else
{
result = CategoryExpression;
}
类似
Find(x => x.Id == 4 && x.Secured == false);