LIKE operator in LINQ

前端 未结 14 1143
一生所求
一生所求 2020-11-27 16:29

Is there any way to compare strings in a C# LINQ expression similar to SQL\'s LIKE operator?

Suppose I have a string list. On this list I want to search

14条回答
  •  生来不讨喜
    2020-11-27 16:56

    Well... sometimes it may be uncomfortable to use Contains, StartsWith or EndsWith especially when searching value determine LIKE statment e.g. passed 'value%' require from developer to use StartsWith function in expression. So I decided to write extension for IQueryable objects.

    Usage

    // numbers: 11-000-00, 00-111-00, 00-000-11
    
    var data1 = parts.Like(p => p.Number, "%11%");
    // result: 11-000-00, 00-111-00, 00-000-11
    
    var data2 = parts.Like(p => p.Number, "11%");
    // result: 11-000-00
    
    var data3 = parts.Like(p => p.Number, "%11");
    // result: 00-000-11
    

    Code

    public static class LinqEx
    {
        private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains");
        private static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
        private static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
    
        public static Expression> LikeExpression(Expression> property, string value)
        {
            var param = Expression.Parameter(typeof(TSource), "t");
            var propertyInfo = GetPropertyInfo(property);
            var member = Expression.Property(param, propertyInfo.Name);
    
            var startWith = value.StartsWith("%");
            var endsWith = value.EndsWith("%");
    
            if (startWith)
                value = value.Remove(0, 1);
    
            if (endsWith)
                value = value.Remove(value.Length - 1, 1);
    
            var constant = Expression.Constant(value);
            Expression exp;
    
            if (endsWith && startWith)
            {
                exp = Expression.Call(member, ContainsMethod, constant);
            }
            else if (startWith) 
            {
                exp = Expression.Call(member, EndsWithMethod, constant);
            }
            else if (endsWith)
            {
                exp = Expression.Call(member, StartsWithMethod, constant);
            }
            else
            {
                exp = Expression.Equal(member, constant);
            }
    
            return Expression.Lambda>(exp, param);
        }
    
        public static IQueryable Like(this IQueryable source, Expression> parameter, string value)
        {
            return source.Where(LikeExpression(parameter, value));
        }
    
        private static PropertyInfo GetPropertyInfo(Expression expression)
        {
            var lambda = expression as LambdaExpression;
            if (lambda == null)
                throw new ArgumentNullException("expression");
    
            MemberExpression memberExpr = null;
    
            switch (lambda.Body.NodeType)
            {
                case ExpressionType.Convert:
                    memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
                    break;
                case ExpressionType.MemberAccess:
                    memberExpr = lambda.Body as MemberExpression;
                    break;
            }
    
            if (memberExpr == null)
                throw new InvalidOperationException("Specified expression is invalid. Unable to determine property info from expression.");
    
    
            var output = memberExpr.Member as PropertyInfo;
    
            if (output == null)
                throw new InvalidOperationException("Specified expression is invalid. Unable to determine property info from expression.");
    
            return output;
        }
    }
    

提交回复
热议问题