如何检查Linq Expression值是否为null

时间:2018-02-13 15:24:54

标签: c# linq

我有一个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);
    }

1 个答案:

答案 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; }
}