我的WCF数据服务(四)涅槃

网站以上面的方式运行了一段时间,速度很好。但是,心中隐隐有所不甘,本来 Lambda 表达式就是为了方便,如果都这样写,反倒要费事了。既然我能自己构建表达式,为什么不能改造已有的表达式呢?于是经过各种研究,反复试验,终于出炉了我觉得比较满意的一个表达式转换类。当用户在调用查询时,会使用这个类重建一个表达式,把里面的进程内变量替换成值。代码如下:

using System.Collections.Generic;
namespace System.Linq.Expressions
{
    public class ExpressionRebuilder<T, Tk> where T : class
    {
        public Expression<Func<T, Tk>> Result;
        public ExpressionRebuilder(Expression<Func<T, Tk>> predicate)
        {
            Result = Expression.Lambda(Rebuild(predicate.Body), predicate.Parameters) as Expression<Func<T, Tk>>;
        }

        private Expression Rebuild(Expression exp)
        {
            if (exp is BinaryExpression)
                return Rebuild((BinaryExpression)exp);
            else if (exp is MethodCallExpression)
                return Rebuild((MethodCallExpression)exp);
            else if (exp is ConstantExpression)
                return exp;
            else if (exp is UnaryExpression)
                return Rebuild((UnaryExpression)exp);
            else if (exp is MemberExpression)
                return Rebuild((MemberExpression)exp);
            else if (exp is ConditionalExpression)
                return Rebuild((ConditionalExpression)exp);
            else
                return exp;
        }

        private Expression Rebuild(UnaryExpression @Unary)
        {
            ExpressionType nt = @Unary.NodeType;
            Expression op = @Unary.Operand;
            if (nt == ExpressionType.Not)
            {
                op = Rebuild(op);
                return Expression.Not(op);
            }
            else if (nt == ExpressionType.Convert)
            {
                if (op is MemberExpression)
                {
                    op = Rebuild((MemberExpression)op);
                }
                if (op is ConstantExpression)
                {
                    op = Expression.Convert(op, @Unary.Type);
                    op = Expression.Constant(Expression.Lambda(op).Compile().DynamicInvoke(), @Unary.Type);
                    return op;
                }
                else
                    return Expression.Convert(op, @Unary.Type);
            }
            else
                return @Unary;
        }

        private Expression Rebuild(MethodCallExpression @MethodCall)
        {
            var a = @MethodCall.Arguments;
            var rstArguments = new List<Expression>();
            var obj = @MethodCall.Object;
            if (obj != null)
            {
                if (obj.Type == typeof(System.Web.HttpRequest) && @MethodCall.Method.Name == "get_Item")
                {
                    System.Web.HttpRequest swhr = (System.Web.HttpRequest)(((ConstantExpression)Rebuild((MemberExpression)obj)).Value);
                    object o = ((ConstantExpression)a[0]).Value;
                    string ag = swhr[o.ToString()];
                    return Expression.Constant(ag, typeof(string));
                }
                obj = Rebuild(obj);
            }

            foreach (var aa in a)
            {
                var bb = Rebuild(aa);
                rstArguments.Add(bb);
            }
            MethodCallExpression mce;
            if (obj == null)
            {
                mce = Expression.Call(@MethodCall.Method, rstArguments);
            }
            else
            {
                mce = Expression.Call(obj, @MethodCall.Method, rstArguments);
            }
            return ReduceMethodCallExpression(mce);
        }

        Expression ReduceMethodCallExpression(MethodCallExpression @MethodCall)
        {
            object o = @MethodCall.Object;
            if (o != null && !(o is ConstantExpression))
                return @MethodCall;
            bool allTrue = true;
            foreach (Expression a in @MethodCall.Arguments)
            {
                if (!(a is ConstantExpression))
                {
                    allTrue = false;
                    break;
                }
            }
            if (!allTrue)
                return @MethodCall;
            List<object> lo = new List<object>();
            foreach (Expression a in @MethodCall.Arguments)
            {
                lo.Add(((ConstantExpression)a).Value);
            }
            object rsst = @MethodCall.Method.Invoke(o == null ? o : ((ConstantExpression)o).Value, lo.ToArray());

            return Expression.Constant(rsst);
        }

        private Expression Rebuild(BinaryExpression @Binary)
        {
            Expression l = @Binary.Left;
            Expression r = @Binary.Right;

            l = Rebuild(l);

            r = Rebuild(r);

            if (l is ConstantExpression && r is ConstantExpression)
            {
                if (@Binary.NodeType == ExpressionType.ArrayIndex)
                {
                    return Expression.Constant(((object[])(((ConstantExpression)l).Value))[(int)((ConstantExpression)r).Value]);
                }
            }
            if (@Binary.NodeType == ExpressionType.AndAlso)
            {
                if (l is ConstantExpression)
                {
                    var lc = (ConstantExpression)l;
                    if (lc.Type == typeof(bool))
                    {
                        bool lcb = (bool)lc.Value;
                        if (lcb)
                            return r;
                        else
                            return Expression.Constant(false, typeof(bool));
                    }
                }
                if (r is ConstantExpression)
                {
                    var rc = (ConstantExpression)r;
                    if (rc.Type == typeof(bool))
                    {
                        bool rcb = (bool)rc.Value;
                        if (rcb)
                            return l;
                        else
                            return Expression.Constant(false, typeof(bool));
                    }
                }
            }
            BinaryExpression be = Expression.MakeBinary(@Binary.NodeType, l, r, @Binary.IsLiftedToNull, @Binary.Method);
            if (l is ConstantExpression && r is ConstantExpression)
            {
                try
                {
                    object o = Expression.Lambda(be).Compile().DynamicInvoke();
                    return Expression.Constant(o, be.Type);
                }
                catch (Exception) { }
            }
            return be;
        }

        private Expression Rebuild(ConditionalExpression Ce)
        {
            Expression newTest = Rebuild(Ce.Test);
            Expression newIfTrue = Rebuild(Ce.IfTrue);
            Expression newIfFalse = Rebuild(Ce.IfFalse);
            if (newTest is ConstantExpression)
            {
                ConstantExpression nt = (ConstantExpression)newTest;
                if (nt.Type == typeof(bool))
                {
                    bool b = (bool)nt.Value;
                    if (b)
                        return newIfTrue;
                    else
                        return newIfFalse;
                }
            }
            return Expression.Condition(newTest, newIfTrue, newIfFalse);
        }

        private Expression Rebuild(MemberExpression Me)
        {
            if (Me.Expression != null && Me.Expression.NodeType == ExpressionType.Parameter)
            {
                return Me;
            }
            var rst = Me.Expression;
            if (rst is MemberExpression)
            {
                rst = Rebuild((MemberExpression)rst);
            }
            try
            {
                object o = Expression.Lambda(Me).Compile().DynamicInvoke();
                return Expression.Constant(o, Me.Type);
            }
            catch (Exception) { }
            //下面的内容是先写的,有时会报错,后来使用了上边的DynamicInvoke()
            if (!(rst is ConstantExpression))
                return Me;
            var b = ((ConstantExpression)rst).Value;
            System.Reflection.FieldInfo fi;
            fi = b.GetType().GetField(Me.Member.Name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            if (fi == null)
                fi = b.GetType().GetField(Me.Member.Name);
            if (fi != null)
            {
                object c = fi.GetValue(b);
                ConstantExpression ce = Expression.Constant(c, Me.Type);
                return ce;
            }
            else
            {
                System.Reflection.PropertyInfo pi = b.GetType().GetProperty(Me.Member.Name);
                if (pi == null)
                    pi = b.GetType().GetProperty(Me.Member.Name, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                object c = pi.GetValue(b);
                ConstantExpression ce = Expression.Constant(c, Me.Type);
                return ce;
            }
        }
    }
}

调用时这样:

predicate = new System.Linq.Expressions.ExpressionRebuilder<Model.XXX, bool>(predicate).Result;

写到了扩展方法里:

public static Expression<Func<T,Tk>> Rebuild<T,Tk>(this Expression<Func<T, Tk>> predicate) where T:class
        {
            return new System.Linq.Expressions.ExpressionRebuilder<T, Tk>(predicate).Result;
        }

在BLL.XXX里,只要这样一句就够了:

public List<T> GetList<Tm>(int pageSize, int pageIndex, Expression<Func<T, bool>> Efma, Expression<Func<T, Tm>> orderBy, bool desc, out int recordCount)
{
     Efma = Efma.Rebuild();
     return WCF.GetList(pageSize, pageIndex, Efmas, keySelector, desc, out recordCount);
}

这几年中,网站扩大了,手下多了几个人。他们调用数据服务时,和调用进程内的数据没有什么区别,再也不用写很长的代码,对他们来说是透明的。
最终实现了类似内存数据库的东西,速度比数据库要快几倍,并发性能也要高很多,因为是直接从内存检索数据。
这个类是我第一个比较满意的作品,如果有什么问题和意见,欢迎评论。

猜你喜欢

转载自blog.csdn.net/zl33842902/article/details/52250450