【问题标题】:Dealing with nulls indynamically created linq expression处理动态创建的 linq 表达式中的空值
【发布时间】:2013-09-15 14:26:01
【问题描述】:

我正在基于字符串数组动态创建 Linq 表达式,但遇到了问题。创建表达式并将其括起来的方式导致它在 Id 3 上抛出对象空引用。它创建此表达式,如果正确括起来,它将不会评估表达式的后半部分,也不会抛出我假设的错误。任何人都有创建表达式的方法,所以它不会像这样用括号括起来吗?

{x => ((True And x.Id.ToString().ToLower().Contains("John")) Or ((x.Name != null) And     x.Name.ToString().ToLower().Contains("John")))}

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Test
{
    public void someMethod()
    {
        var x = new List<Person>(new Person[] { 
            new Person { Id = 1, Name = "Jerry" },
            new Person { Id = 2, Name = "Mary" },
            new Person { Id = 3, Name = null },
            new Person { Id = 4, Name = "John" },
            new Person { Id = 5, Name = "Amy" }
        });

        var columns = new List<string>(new string[] {
            "Name",
            "Id"
        });
        var searchTerm = "John";

        var searchColumns = columns.Select(a => new { ColName = a });


        var type = typeof(Person);

        ParameterExpression paramExpr = Expression.Parameter(type, "x");
        Expression body = null;

        var piList = new List<PropertyInfo>();

        foreach (var s in searchColumns)
            piList.Add(type.GetProperty(s.ColName));

        if (piList[0].PropertyType.IsPrimitive || piList[0].PropertyType.Equals(typeof(DateTime)))
            body = Expression.Constant(true);
        else
            body = Expression.NotEqual(Expression.Property(paramExpr, piList[0]), Expression.Constant(null, piList[0].PropertyType));

        body = Expression.And(body,
                    Expression.Call(
                            Expression.Call(
                                Expression.Call(
                                    Expression.Property(paramExpr, piList[0]),
                                    typeof(Convert).GetMethod("ToString", Type.EmptyTypes)
                                ),
                                typeof(string).GetMethod("ToLower", new Type[0])
                            ),
                            typeof(string).GetMethod("Contains"),
                            Expression.Constant(searchTerm.ToLower())
                        ));

        for (int i = 1; i < piList.Count; i++)
        {
            Expression body1 = null;

            if (piList[i].PropertyType.IsPrimitive || piList[i].PropertyType.Equals(typeof(DateTime)))
                body1 = Expression.Constant(true);
            else
                body1 = Expression.NotEqual(Expression.Property(paramExpr, piList[i]), Expression.Constant(null, piList[i].PropertyType));

            body =
                Expression.Or(body,
                    Expression.And(body1,
                        Expression.Call(
                            Expression.Call(
                                Expression.Call(
                                    Expression.Property(paramExpr, piList[i]),
                                    typeof(Convert).GetMethod("ToString", Type.EmptyTypes)
                                ),
                                typeof(string).GetMethod("ToLower", new Type[0])
                            ),
                            typeof(string).GetMethod("Contains"),
                            Expression.Constant(searchTerm.ToLower())
                        )
                    ));
        }

        var lambda = Expression.Lambda<Func<Person, bool>>(body, paramExpr);
    }
}

【问题讨论】:

    标签: c# linq null


    【解决方案1】:

    为什么不只构建其中之一。它们都避免了Name 的空值问题。

    (x.Name ?? "").IndexOf("John", StringComparison.CurrentCultureIgnoreCase) >= 0
    

    或者,如果你真的想要相等,不要将它包含为子字符串

    string.Equals(x.Name, "John", StringComparison.CurrentCultureIgnoreCase)
    

    顺便说一句 - x.Id 永远不会包含“John”,也不会包含小写字符串。

    此外,您可能需要考虑使用 PredicateBuilder 而不是直接构建表达式。

    【讨论】:

    • 所以这是一个简化版。我实际上正在研究通用类型,所以我不知道将传递哪些字段,这就是我必须使用反射的原因。基本上你可以传递任何列表,它会搜索你的词。我会研究 PredicateBuidler。
    • @EnigmaNeo - 如果您最终使用表达式方法,请考虑使用 Convert.ChangeType 而不是 ToString 如果是 LINQ/SQL 或 LINQ/EF to MSSQL,则不需要进行大小写任何一个。如果是对象,考虑定义一个静态相等比较方法,可以容忍空值或不同的对象类型。
    • 感谢您的想法。我认为这将解决我的问题。它是对象的 linq,所以我可能只创建一个静态函数来检查它。应该很容易。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    相关资源
    最近更新 更多