有没有办法从Expression<Func<T,bool>>
构建Expression<Func<T>>
?
例如对于班级
public class MyClass
{
public int Prop1{get;set;}
public int Prop2{get;set;}
public int Prop3{get;set;}
}
如果Expression<Func<T>>
为() => new MyClass{Prop2 = 5}
,则结果应为x => x.Prop2 == 5
如果Expression<Func<T>>
为() => new MyClass{Prop1 = 1, Prop3 = 3}
,则结果应为x => x.Prop1 == 1 && x.Prop3 == 3
换句话说,是否可以在运行时创建具有任意数量条件的func?
答案 0 :(得分:7)
像这样:
static Expression<Func<T,bool>> Munge<T>(Expression<Func<T>> selector)
{
var memberInit = selector.Body as MemberInitExpression;
if (memberInit == null)
throw new InvalidOperationException("MemberInitExpression is expected");
var p = Expression.Parameter(typeof(T), "x");
Expression body = null;
foreach (MemberAssignment binding in memberInit.Bindings)
{
var comparer = Expression.Equal(
Expression.MakeMemberAccess(p, binding.Member),
binding.Expression);
body = body == null ? comparer : Expression.AndAlso(body, comparer);
}
if (body == null) body = Expression.Constant(true);
return Expression.Lambda<Func<T, bool>>(body, p);
}
答案 1 :(得分:2)
让代码为自己说话:
class Program
{
static Expression<Func<T, bool>> Transform<T>(Expression<Func<T>> expression)
{
var initExpression = expression.Body as MemberInitExpression;
if (initExpression == null)
{
throw new ArgumentException();
}
Expression bodyExpression = Expression.Constant(true);
IEnumerable<MemberBinding> bindings = initExpression.Bindings;
ParameterExpression param = Expression.Parameter(typeof(T));
foreach (var memberBinding in bindings)
{
var memberAssigment = memberBinding as MemberAssignment;
if (memberAssigment == null)
{
throw new ArgumentException();
}
var member = memberAssigment.Member;
var value = memberAssigment.Expression;
bodyExpression = Expression.AndAlso(
bodyExpression,
Expression.Equal(
Expression.MakeMemberAccess(param, member),
value
)
);
}
return Expression.Lambda<Func<T, bool>>(bodyExpression, param);
}
static void Main(string[] args)
{
Expression<Func<MyClass>> exp = () => new MyClass { Prop1 = 1, Prop3 = 3 };
var result = Transform(exp);
var lambda = result.Compile();
var array = new[]
{
new MyClass { Prop1 = 1, Prop3 = 3 },
new MyClass { Prop1 = 1, Prop2 = 2, Prop3 = 3 },
new MyClass { Prop1 = 1, Prop3 = 1 },
new MyClass { Prop1 = 3, Prop3 = 3 },
new MyClass { Prop1 = 3, Prop3 = 1 },
new MyClass()
};
foreach (var o in array)
{
Console.WriteLine(lambda(o));
}
}
}