首页 新闻 会员 周边

关于表达式树的缓存

0
悬赏园豆:5 [已解决问题] 解决于 2017-03-28 10:39

请问,如何一般要缓存一个表达式树是不是把Compile之后的Func或者是Action放在Dictionary里面。

现在有一个问题,我想缓存这样的表达式树应该怎么做:

 ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "a");
            MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, orderField);
            MethodCallExpression methodExpression = Expression.Call(memberExpression, typeof(Convert).GetMethod("ToString", new Type[] { }));
            Expression<Func<TSource, string>> expression = Expression.Lambda<Func<TSource, string>>(methodExpression, parameterExpression);

            Func<TSource, string> func = expression.Compile();

            if (orderFunc == "asc")
            {
                return source.OrderBy(func);
            }
            else
            {
                return source.OrderByDescending(func);
            }

我想当然的这么做:

public static class LinqExtend<TSource>
    {
        static Dictionary<string, Func<TSource, string>> dic = new Dictionary<string, Func<TSource, string>>();

        public static IEnumerable<TSource> Order<TSource>(this IEnumerable<TSource> source, string orderField, string orderFunc = "asc")
        {
            if (source == null)
            {
                throw new Exception("source is null");
            }

            Func<TSource, string> func;
            if (!dic.TryGetValue(typeof(TSource).FullName + orderField, out func))
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "a");
                MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, orderField);
                MethodCallExpression methodExpression = Expression.Call(memberExpression, typeof(Convert).GetMethod("ToString", new Type[] { }));
                Expression<Func<TSource, string>> expression = Expression.Lambda<Func<TSource, string>>(methodExpression, parameterExpression);

                func = expression.Compile();
                dic.Add(typeof(TSource).FullName + orderField, func);
            }
            if (orderFunc == "asc")
            {
                return source.OrderBy(func);
            }
            else
            {
                return source.OrderByDescending(func);
            }
        }
    }

可是会划红线:

 

谁知道这个问题,应该怎么解决?

CodeBear的主页 CodeBear | 初学一级 | 园豆:3
提问于:2017-03-28 09:52
< >
分享
最佳答案
0

public static IEnumerable<TSource> Order<TSource>(this IEnumerable<TSource> source, string orderField, string orderFunc = "asc")

这个地方Order后面不用再申明范T

Order(this....)

收获园豆:5
Daniel Cai | 专家六级 |园豆:10424 | 2017-03-28 09:59

大神,这么修改之后,

就无法使用这个排序的扩展方法了。这个应该怎么办呢?

CodeBear | 园豆:3 (初学一级) | 2017-03-28 10:05

@CodeBear: 针对你这个场景你这样实现是不对的,承载扩展方法的对象不能是泛型的,如果你拿掉那个class上的泛型约束/定义,则你的dic就会出问题。反之,如果你放弃扩展方法使用普通静态方法则会导致另一个问题:

.net泛型的实现会导致你这个class对象针对每种泛T实际类型创建不同的的类型,比如LinqExtend`1[User],LinqExtend`1[Student]等,这样你那个本来想作为cache的字典就没任何意义了(针对每种泛T类型都会有自己的dic)

 

如果你这里只是想实现Order的功能可以直接使用Enumerable.OrderBy的扩展方法即可

Daniel Cai | 园豆:10424 (专家六级) | 2017-03-28 10:20

@Daniel Cai: 谢谢了,可能这样的场景是有问题,我主要是想学习一下表达式树的,自带的Enumerable.OrderBy的方法,只能应用于 排序字段 已知的情况下,比如 

list.OrderBy(a=>a.Age);

list.OrderBy(a=>a.BirthDay)

但是对于排序字段未知的场景,就无能为力了,所以我想用下表达式树解决这个问题(当然我知道反射也可以解决,只是现在我想学习表达式树),现在表达式树是写出来了,但是 不知道怎么把最终生成的委托给缓存起来。

可能针对于这种场景,表达式树并不适用。

CodeBear | 园豆:3 (初学一级) | 2017-03-28 10:31

@CodeBear: 表达式树我是感觉有点烧脑,而且限制比较多(如果最后是生成委托的话),这块还不如直接上il,难度差不多但没任何限制。

Daniel Cai | 园豆:10424 (专家六级) | 2017-03-28 10:38
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册