我在使用C#动态生成的lambda表达式时遇到了一些问题。
考虑以下情况:
public class Person {
public long Id { get; set; }
public string Name { get; set; }
}
List<Person> persons = new List<Person> () {
new Person { Id = 1, Name = "Foo" },
new Person { Id = 2, Name = "Bar" },
new Person { Id = 3, Name = "Baz" },
new Person { Id = 4, Name = null },
};
现在,执行以下代码
ParameterExpression param = Expression.Parameter(typeof(Person), "arg");
Expression prop = Expression.Property(param, "Name");
Expression value = Expression.Constant("bar");
Type type = prop.Type;
MethodInfo toLower = typeof(String).GetMethod("ToLower", Type.EmptyTypes);
Expression expLower = Expression.Call(prop, toLower);
Expression clausule = Expression.Call(expLower, type.GetMethod("Contains", new[] { type }), value);
Expression notNull = Expression.NotEqual(prop, Expression.Constant(null));
clausule = Expression.And(notNull, clausule);
var exp = Expression.Lambda<Func<T, bool>>(clausule, param);
上面的代码生成以下表达式。
//arg => ((arg.Name != null) And (arg.Name.ToLower().Contains("bar")))
现在,尝试将其应用于我的列表。
下面的过滤器有效
var filteredListThatWorks = persons.Where(arg => arg.Name != null && arg.Name.ToLower().Contains("bar")).ToList();
下面的一个抛出Null对象的异常(由于ID 4名称)
var filteredListThatGivesExp = persons.Where(exp.Compile()).ToList();
当由lambda生成时,相同的表达式在手动输入时会抛出exp。 有谁知道解决这个问题的方法吗?
Br,
答案 0 :(得分:6)
And
是&
;您要使用AndAlso
(&&
):
clausule = Expression.AndAlso(notNull, clausule);
如有疑问,sharplab.io是一个很好的工具。如果我使用:
Expression<Func<Person, bool>> filter
= arg => arg.Name != null && arg.Name.ToLower().Contains("bar");
它告诉我它的编译等效于:
// ...
BinaryExpression body = Expression.AndAlso(left, Expression.Call(instance, method, obj));
// ...
(请注意,尽管它必须包含一些指令,因为它可以编译为实际上无法用原始C#表达的东西)