找了很久,原來就在 梨子給的範例裡。
假設有兩個 expression: e1, e2
            var combineBody = Expression.AndAlso(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
            var finalExpression = Expression.Lambda<Func<TestClass, bool>>(combineBody, e1.Parameters).Compile();
同理,把上面的 AndAlso 換成 OrElse 就可以用 Or 合併。
即使只有兩行,還是不太可能背起來,所以當然要來做一下擴充
    public static class ExpressionExtension
    {
        public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> e1, Expression<Func<T, bool>> e2)
        {
            var combineE = Expression.AndAlso(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
            return Expression.Lambda<Func<T, bool>>(combineE, e1.Parameters);
        }
        public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> e1, Expression<Func<T, bool>> e2)
        {
            var combineE = Expression.OrElse(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
            return Expression.Lambda<Func<T, bool>>(combineE, e1.Parameters);
        }
    }
使用範例:
            Expression<Func<Market, bool>> e1 = e => e.Is_Deleted == isDelete;
            Expression<Func<Market, bool>> e2 = e => string.IsNullOrEmpty(marketNo) || e.MarketNo.ToUpper().Contains(marketNo.ToUpper());
            return new
            {
                andMarkets = Ds.PageContext.ShopBandContext.Markets.Where(e1.AndAlso(e2)).ToList(),
                orMarkets = Ds.PageContext.ShopBandContext.Markets.Where(e1.OrElse(e2)).ToList(),
            };
 再補兩個擴充, 可以把多個 Expression 用 AndAlso 或 OrElse 串在一起:
        public static Expression<Func<T, bool>> OrElseAll<T>(this IEnumerable<Expression<Func<T, bool>>> exps)
        {
            if (exps.Count() == 1)
            {
                return exps.First();
            }
            var e0 = exps.First();
            var orExp = exps.Skip(1).Aggregate(e0.Body, (x, y) => Expression.OrElse(x, Expression.Invoke(y, e0.Parameters[0])));
            return Expression.Lambda<Func<T, bool>>(orExp, e0.Parameters);
        }
        public static Expression<Func<T, bool>> AndAlsoAll<T>(this IEnumerable<Expression<Func<T, bool>>> exps)
        {
            if (exps.Count() == 1)
            {
                return exps.First();
            }
            var e0 = exps.First();
            var orExp = exps.Skip(1).Aggregate(e0.Body, (x, y) => Expression.AndAlso(x, Expression.Invoke(y, e0.Parameters[0])));
            return Expression.Lambda<Func<T, bool>>(orExp, e0.Parameters);
        }
使用範例:
            Expression<Func<Market, bool>> q = e =>
            e.Is_Deleted == "N"
            && (string.IsNullOrEmpty(marketNo) || e.MarketNo.ToLower().Contains(marketNo.ToLower()))
            && (string.IsNullOrEmpty(isCombination) || isCombination != "Y" || e.TypeEnum == 200);
            if (!string.IsNullOrEmpty(name))
            {
                var nameList = name.Split(',').Select(e => e.Trim())
                    .Where(e => !string.IsNullOrEmpty(e));
                if (nameList.Any())
                {
                    q = q.AndAlso(nameList
                        .Select(s => (Expression<Func<Market, bool>>)(e => e.Name.ToLower().Contains(s.ToLower())))
                        .OrElseAll());
                }
            }
另外在 google,整理了 stackoverflow 幾篇文章之後得到的另一個方法,比較複雜, 不過可以讓人理解一下 Expression 比較底層的東西,也留下來參考一下。
    internal class MergeTool : ExpressionVisitor
    {
        private readonly ParameterExpression _parameter;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return base.VisitParameter(_parameter);
        }
        internal MergeTool(ParameterExpression parameter)
        {
            _parameter = parameter;
        }
        public static Expression<Func<T, bool>> MergedExpression<T>(Expression<Func<T, bool>> e1, Expression<Func<T, bool>> e2)
        {
            ParameterExpression param = Expression.Parameter(typeof(T));
            BinaryExpression MergeBody = Expression.AndAlso(e1.Body, e2.Body);
            var ReplacedBody = (BinaryExpression)new MergeTool(param).Visit(MergeBody);
            return Expression.Lambda<Func<T, bool>>(ReplacedBody, param);
        }
    }
使用時要 Compile
            var mergedExpression = MergeTool.MergedExpression(e1, e2);
            var list = testList.Where(mergedExpression.Compile());