3

I have the following code block I am using to perform some dynamic filtering on a generic IQueryable list

    private static MethodInfo miTL = typeof(String).GetMethod("ToLower", Type.EmptyTypes);

    public static IQueryable<T> Where<T>(IQueryable<T> source, string member, object value)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (member == null)
        {
            throw new ArgumentNullException("member");
        }
        if (value == null)
        {
            throw new ArgumentNullException("value");
        }

        if (value is string && !string.IsNullOrWhiteSpace(value.ToString()))
        {
            //If the type is string, force lowercase equals comparison for both sides.
            value = value.ToString().ToLower();

            var parameter = Expression.Parameter(typeof(T), "item");
            var parameterProperty = Expression.Property(parameter, member);

            //ToLower dynamic expression
            var dynamicExpression = Expression.Call(parameterProperty, miTL);

            var constantValue = Expression.Constant(value);
            var equalsExpression = Expression.Equal(dynamicExpression, constantValue);

            var lambdaExpression = Expression.Lambda<Func<T, bool>>(equalsExpression, parameter);

            return source.Where(lambdaExpression);
        }
        else
        {
            var item = Expression.Parameter(typeof(T), "item");
            var prop = Expression.Property(item, member);
            var soap = Expression.Constant(value);
            var equal = Expression.Equal(prop, soap);
            var lambda = Expression.Lambda<Func<T, bool>>(equal, item);
            return source.Where(lambda);
        }
    }

This all works fine - apart from the possibility of my source containing null values, which then returns a null reference exception.

It directly translates to (when the field is "Counterparty" :- {item => (item.Counterparty.ToLower() == "name of counterparty")}

What I actually need in Lambda expression form is :-

{item => !string.IsNullEmptyOrWhitespace(item.Counterparty) && (item.Counterparty.ToLower() == "name of counterparty")}

Any ideas how to achieve this dynamically?

--REVIEWED--

Here is the whole replacement code, using a much nicer string.Equals check

    public static IQueryable<T> Where<T>(IQueryable<T> source, string member, object value)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (member == null)
        {
            throw new ArgumentNullException("member");
        }
        if (value == null)
        {
            throw new ArgumentNullException("value");
        }

        if (value is string && !string.IsNullOrWhiteSpace(value.ToString()))
        {
            var parameter = Expression.Parameter(typeof(T), "item");
            var parameterProperty = Expression.Property(parameter, member);

            var body =
                Expression.AndAlso(
                    Expression.Not(
                        Expression.Call(typeof(string), "IsNullOrEmpty", null, parameterProperty)
                    ),
                    Expression.Call(typeof(string), "Equals", null,
                        parameterProperty, Expression.Constant(value),
                        Expression.Constant(System.StringComparison.InvariantCultureIgnoreCase))
                );

            var body2 = Expression.Call(typeof(string), "Equals", null,
                parameterProperty, Expression.Constant(value),
                Expression.Constant(System.StringComparison.InvariantCultureIgnoreCase));

            var lambdaExpression = Expression.Lambda<Func<T, bool>>(body, parameter);

            return source.Where(lambdaExpression);
        }
        else
        {
            var item = Expression.Parameter(typeof(T), "item");
            var prop = Expression.Property(item, member);
            var soap = Expression.Constant(value);
            var equal = Expression.Equal(prop, soap);
            var lambda = Expression.Lambda<Func<T, bool>>(equal, item);
            return source.Where(lambda);
        }
    }
0

1 Answer 1

3

A literal translation would be something like:

var body =
    Expression.AndAlso(
        Expression.Not(
            Expression.Call(typeof(string), "IsNullOrWhiteSpace", null,
                                                       parameterProperty)
        ),
        Expression.Equal(
            Expression.Call(parameterProperty, "ToLower", null),
            Expression.Constant("name of counterparty")
        )
    );

However, you would do well to look at the various string.Equals overloads. For example:

var body = Expression.Call(typeof(string), "Equals", null,
    parameterProperty, Expression.Constant("name of counterparty"),
    Expression.Constant(System.StringComparison.InvariantCultureIgnoreCase));
Sign up to request clarification or add additional context in comments.

1 Comment

Hi Marc, I would have preferred to use something more like !string.IsNullEmptyOrWhitespace(item.Value) && item.Value.Equals(otherLiteral, CurrentCulture.IgnoreCase) - but I couldn't figure out a way of doing this either?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.