请问,如何一般要缓存一个表达式树是不是把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); } } }
可是会划红线:
谁知道这个问题,应该怎么解决?
public static IEnumerable<TSource> Order<TSource>(this IEnumerable<TSource> source, string orderField, string orderFunc = "asc")
这个地方Order后面不用再申明范T
Order(this....)
大神,这么修改之后,
就无法使用这个排序的扩展方法了。这个应该怎么办呢?
@CodeBear: 针对你这个场景你这样实现是不对的,承载扩展方法的对象不能是泛型的,如果你拿掉那个class上的泛型约束/定义,则你的dic就会出问题。反之,如果你放弃扩展方法使用普通静态方法则会导致另一个问题:
.net泛型的实现会导致你这个class对象针对每种泛T实际类型创建不同的的类型,比如LinqExtend`1[User],LinqExtend`1[Student]等,这样你那个本来想作为cache的字典就没任何意义了(针对每种泛T类型都会有自己的dic)
如果你这里只是想实现Order的功能可以直接使用Enumerable.OrderBy的扩展方法即可
@Daniel Cai: 谢谢了,可能这样的场景是有问题,我主要是想学习一下表达式树的,自带的Enumerable.OrderBy的方法,只能应用于 排序字段 已知的情况下,比如
list.OrderBy(a=>a.Age);
list.OrderBy(a=>a.BirthDay)
但是对于排序字段未知的场景,就无能为力了,所以我想用下表达式树解决这个问题(当然我知道反射也可以解决,只是现在我想学习表达式树),现在表达式树是写出来了,但是 不知道怎么把最终生成的委托给缓存起来。
可能针对于这种场景,表达式树并不适用。
@CodeBear: 表达式树我是感觉有点烧脑,而且限制比较多(如果最后是生成委托的话),这块还不如直接上il,难度差不多但没任何限制。