手工把LINQ转成表达式(二) 准备工作
来源:互联网 发布:安装示意图制作软件 编辑:程序博客网 时间:2024/05/01 11:01
先来看一句简单的LINQ语句:
from item in Source
select item
这里如果写成方法调用的话就是
Source.Select(item => item)
这意味着in后面的是作为方法调用的发起方(invoker) ,from是定义表达式参数,select才是真正的方法本身。
再来看个多语句的例子:
from a in A
where a != null
select a
不考虑优化的情况下写成方法应该是
A.Where(a => a != null).Select(a => a)
也就是说可以认为前一句的输出是后一句的输入并且后一句还需要用到前一句的参数别名,在解析的时候需要一种机制能满足这种要求,为了简化处理不再采用递归方式分析,而是用了这么一个结构保存解析LINQ时所有要用到的上下文场景:
internal class LINQContext { public ParameterExpression Parameter { get; set; } public string Name { get; set; } public Expression Self { get; set; } private ParameterExpression nextParameter; public ParameterExpression NextParameter { get { if (nextParameter != null) return nextParameter; nextParameter = IsFirst ? Parameter : Expression.Parameter(Self.GetElementType(), Name); return nextParameter; } set { nextParameter = value; } } private bool isFirst = false; public bool IsFirst { get { return isFirst; } set { isFirst = value; } } }
Parameter是当前的输入参数,Name代表参数名,Self是当前语句的表达式,NextParameter是表示为下一句LINQ的输入参数,IsFirst标志位表示是否是第一个from语句(在介绍from时详细说)。
这里顺便说一下,grammar又更新了,这次把所有赋值运算符全部移出二元运算符,目前的解析器暂时不支持带赋值运算符的表达式解析。
有了这个结构我们就可以轻松把一句LINQ中的每个操作语句的上下文给保存下来便于转换了:
private Stack<LINQContext> _linqVariables;
这里用了栈来保存linq语句的上下文,实际实现下来感觉也并非必要,不过用栈的话可以逆推整个操作过程,对代码调试还是有点帮助的。
先通过grammar对LINQ语句解析后得到的是每一句linq的数组,所以转换入口就这么写了:
private Expression ProcessLINQ(ParseTreeNode expNode) { _linqVariables = new Stack<LINQContext>(); Expression linq = Expression.Empty(); foreach (var child in expNode.ChildNodes) { linq = ProcessQueryExpression(child); } return linq; }
可以注意到,其实最后一句linq被转换后返回的才是完整的表达式,其余中间产生的表达式都入栈了返回值直接被忽略,这里用递归的话可以节省那个栈但是调试起来就麻烦了。
linq语句对应的方法定义为:
#region ExtensionMethods extensionMethods["select"] = typeof(Queryable).GetExtensionMethod("Select", typeof(IQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>))); extensionMethods["let"] = extensionMethods["select"]; extensionMethods["from"] = typeof(Queryable).GetExtensionMethod("SelectMany", typeof(IQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>)), typeof(Expression<>).MakeGenericType(typeof(Func<,,>))); extensionMethods["group"] = typeof(Queryable).GetExtensionMethod("GroupBy", typeof(IQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>))); extensionMethods["join"] = typeof(Queryable).GetExtensionMethod("Join", typeof(IQueryable<>), typeof(IEnumerable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>)), typeof(Expression<>).MakeGenericType(typeof(Func<,>)), typeof(Expression<>).MakeGenericType(typeof(Func<,,>))); extensionMethods["groupjoin"] = typeof(Queryable).GetExtensionMethod("GroupJoin", typeof(IQueryable<>), typeof(IEnumerable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>)), typeof(Expression<>).MakeGenericType(typeof(Func<,>)), typeof(Expression<>).MakeGenericType(typeof(Func<,,>))); extensionMethods["orderby"] = typeof(Queryable).GetExtensionMethod("OrderBy", typeof(IQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>))); extensionMethods["orderbydescending"] = typeof(Queryable).GetExtensionMethod("OrderByDescending", typeof(IQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>))); extensionMethods["thenby"] = typeof(Queryable).GetExtensionMethod("ThenBy", typeof(IOrderedQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>))); extensionMethods["thenbydescending"] = typeof(Queryable).GetExtensionMethod("ThenByDescending", typeof(IOrderedQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>))); extensionMethods["where"] = typeof(Queryable).GetExtensionMethod("Where", typeof(IQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>))); extensionMethods["DefaultIfEmpty"] = typeof(Enumerable).GetExtensionMethod("DefaultIfEmpty", typeof(IEnumerable<>)); #endregion
这里只把DefaultIfEmpty这个扩展单独拿出来是为了支持left join语句,其他扩展方法就先不支持了。
在接下来的分析过程中,都是通过模仿C#编译LINQ产生的表达式来生成我们自己的表达式的,并且忽略了优化。
最新代码下载http://tinynetevent.googlecode.com/files/ExpressionParser0815.zip
- 手工把LINQ转成表达式(二) 准备工作
- 手工把LINQ转成表达式(一) 基础知识
- 手工把LINQ转成表达式(三) from
- 手工把LINQ转成表达式(五) let
- 手工把LINQ转成表达式(六) join
- 手工把LINQ转成表达式(四) select, group, where, orderby
- 屏幕自适应(二)把dp转成px
- Linq学习__00__准备工作
- LINQ 学习(二)
- linq实例(二)
- LINQ简介(二)
- LINQ体验(二)LINQ to XML
- LINQ学习心得二)LINQ语法详解
- Android项目开发前准备工作(二)
- 如何做好手工测试的准备工作
- 算术表达式转成前缀表达式(波兰表达式)并求值
- LINQ中 int转成string
- Linq 学习笔记(二)
- php 通过文件传数组
- *简单脚本测试--利用date进行文件的创建*
- 数据库生成xml格式
- 如何利用和扩展cms/email模板中的指令
- Java学习大全 之 Struts2
- 手工把LINQ转成表达式(二) 准备工作
- 在SQL+Server中将数据库中的一个表的内容完整的复制到另一个表中
- 遍历结束指定进程演示
- ServerLight内存及网页素材保护
- 巧用while循环避免执行除了异常处理的的另一个处理机制
- Java学习大全 之 Spring2.5
- Java一个简单的监听端口的类
- SQL中字段缺位时的模糊查找
- 我的感悟-----写在离职之后,新工作之前