我有一个lambda表达式x => x.person.parent.Id == someId
,我想检查someId
是否为空。我面临的问题是Id
属性是一个可以为空的整数(即int?
)。这是我的尝试,但如果属性可以为空则它不起作用。任何帮助将不胜感激。谢谢。
private static bool IsNullExpression(Expression exp)
{
if (exp is ConstantExpression constantExpression)
{
return constantExpression.Value == null;
}
return false;
}
public void AddIfNotNull(Expression<Func<T, bool>> exp)
{
// convert expression to binary expression
if (exp.Body is BinaryExpression binaryExpression && (IsNullExpression(binaryExpression.Left) || IsNullExpression(binaryExpression.Right)))
{
// there is a null in expression, we just found it
return;
}
_list.Add(exp);
}
答案 0 :(得分:6)
有几种情况你无法处理。
首先,如果属性和值具有不同的类型,则常量将在需要解包的Convert
LINQ节点(类型为UnaryExpression
)中变形。
其次,如果我们处理捕获的变量,编译器将生成一个额外的对象,变量将转换为该对象的字段,访问该变量的表达式将成为对包含捕获的常量的成员访问对象
private static bool IsNullExpression(Expression exp)
{
// If types are different for example int and int? there will be an extra conversion expression, we need to unwrap this
if (exp is UnaryExpression uExp) exp = uExp.Operand;
// If we are dealing with a captured variable, then teh constant will be the capture object and the value is stored as a member on this object
if (exp is MemberExpression mExp && mExp.Expression is ConstantExpression cExp)
{
object value = mExp.Member is PropertyInfo pInfo ? pInfo.GetValue(cExp.Value) :
mExp.Member is FieldInfo fInfo ? fInfo.GetValue(cExp.Value) :
throw new NotSupportedException();
return value == null;
}
// If we use a simple constant, this is what will be called
if (exp is ConstantExpression constantExpression)
{
return constantExpression.Value == null;
}
return false;
}
// Tested with the following
// Simple constant expressions
TestMethod(p => p.Id == 0);
TestMethod(p => p.Id == null);
// Capture a non null value
int value = 0;
TestMethod(p => p.Id == value);
// Capture a null value
int? nullValue = null;
TestMethod(p => p.Parent.Id == nullValue);
// Testing infrastructure
public static bool TestMethod(Expression<Func<Person, bool>> exp)
{
// If we have a binary expression
if (exp.Body is BinaryExpression binaryExpression && (IsNullExpression(binaryExpression.Left) || IsNullExpression(binaryExpression.Right)))
{
return true;
}
else
{
return false;
}
}
public class Person
{
public int? Id { get; set; }
}