If all the "blahs" (classes) that you will filter have the same structure, you can use a simple method like this. The main difference is that it returns an expression that Linq should parse, and it fills in the entire instance and filters the name instead of just entering the string name.
public static Expression<Func<T, bool>> BuildStringMatch<T>(string searchFor) where T : IHasName { return b => string.IsNullOrEmpty(searchFor) || (b.Name != null && (b.Name.Trim().ToLower().StartsWith(searchFor.Trim().ToLower()) || b.Name.Contains(" " + searchFor))); }
You can use this method as follows:
IQueryable<Blah> blahs = query.Where(BuildStringMatch<Blah>(searchText));
This assumes that all of your classes that you want to filter implement some interface, for example:
public interface IHasName { string Name { get; } }
If you want to filter different properties, I donβt think you can do it with simple code. I believe that you will need to develop an expression with reflection yourself (or using a library that uses reflection) - this is still possible, but much more complicated.
Edit: it looks like you need dynamic behavior, so I borrowed some dtb logic to answer this question and came up with the following:
public static Expression<Func<T, bool>> BuildStringMatch<T>(Expression<Func<T, string>> property, string searchFor) { var searchForExpression = Expression.Constant(searchFor, typeof(string)); return Expression.Lambda<Func<T, bool>>( Expression.OrElse( Expression.Call(typeof(string), "IsNullOrEmpty", null, searchForExpression), Expression.AndAlso( Expression.NotEqual(property.Body, Expression.Constant(null, typeof(string))), Expression.OrElse( Expression.Call(Expression.Call(Expression.Call(property.Body, "Trim", null), "ToLower", null), "StartsWith", null, Expression.Call(Expression.Call(searchForExpression, "Trim", null), "ToLower", null)), Expression.Call(property.Body, "Contains", null, Expression.Call(typeof(string), "Concat", null, Expression.Constant(" "), searchForExpression)) ) ) ), property.Parameters ); }
You would use it like:
IQueryable<Blah> blahs2 = query.Where(BuildStringMatch<Blah>(b => b.Name, searchText));
It is long and detailed, but you can see how it looks like the original method written in direct C # code. Note. I have not tested this code, so there may be a few minor problems - but this is a general idea.