lambda表达式的解析(八) 泛型调用及typeof操作
来源:互联网 发布:怎么查询服务器端口 编辑:程序博客网 时间:2024/06/03 21:21
由于对grammar作了一点修正,所以之前PareeTreeNode的扩展方法GetClrType也需要跟着改了:
public static Type[] GetGenericArguments(this ParseTreeNode node) { var typeArgs = node.GetDescendant("type_argument_list"); if (typeArgs == null) return null; return (from typeChild in node.GetChild("type_ref_list").ChildNodes select typeChild.GetClrType()).ToArray(); } private static Type GetClrType(this ParseTreeNode node) { if (node == null) return null; if (node.GetName() != "qual_name_with_targs") node = node.GetDescendant("qual_name_with_targs"); var isNullable = node.GetChild("qmark_opt").FindTokenAndGetText() == "?"; var typeName = node.FindTokenAndGetText(); var type = ExpressionParser.GetType(typeName); var typeArguments = node.GetGenericArguments(); if (typeArguments != null) type.MakeGenericType(typeArguments); if (isNullable) return typeof(Nullable<>).MakeGenericType(type); return type; } public static Type GetNodeClrType(this ParseTreeNode node) { return node.GetDescendant("qual_name_with_targs").GetClrType(); }
泛型调用时肯定是带完整的泛型参数的,比如func<int, int>(a),所以只需要能正确得到泛型参数列表就能通过反射生成正确的带实参泛型方法,成员访问表达式里关于方法调用表达式修改后的代码片段:
case "member_invoke": var methodName = member.FirstChild.GetValue(); var method = type.GetMethod(methodName); var targs = member.GetGenericArguments(); if (targs != null) { method = method.MakeGenericMethod(targs); }
至于typeof操作则略有不同,首先typeof是在静态编译时就确定的值,所以可以看做一个ConstantExpression。然后typeof操作可以获得带泛型参数的泛型类型,也就是可以typeof(Func<,>),所以解析的时候针对泛型需要两种方式都支持。typeof视为一元运算符,解析的入口为之前介绍的一元运算符处理方法:
private Expression ProcessUnaryExpression(ParseTreeNode expNode) { string op; var first = expNode.FirstChild; var second = expNode.LastChild; switch (first.GetName()) { .... case "typeof_expression": return ProcessTypeofExpression(first); .... }
typeof处理方法:
private Expression ProcessTypeofExpression(ParseTreeNode expNode) { var node = expNode.GetChild("typeof_parenthesized_expression").GetDescendant("type_ref_typeof"); var glist = node.GetDescendant("type_argument_list_opt"); Type type = node.GetNodeClrType(); if (glist != null) { type = Type.GetType(String.Format("{0}`{1}", type.FullName, glist.ChildNodes.Count)); } var rank = node.GetChild("rank_specifiers_opt"); var ranks = rank.GetDescendant("rank_specifiers"); if (ranks != null) { for (int i = ranks.ChildNodes.Count - 1; i >= 0; i--) { var r = ranks.ChildNodes[i]; var rs = r.ChildNodes.Count; type = rs > 1 ? type.MakeArrayType(rs) : type.MakeArrayType(); } } return Expression.Constant(type); }
对于typeof(Func<,>)这种表达式,Func<,>类型就是Func`2,也就是类型名跟一个`符号再跟上参数个数。
而对于typeof(int[][,][,,])这种形式就稍微有点疑惑了,看上去int[][,][,,]的类型应该是Int32[][,][,,],但实际上却是Int32[,,][,][],正好反一反,所以在转换的时候也只能从最后一个开始往前做MakeArrayType了,而且MakeArrayType()与MakeArrayType(1)居然也不一样,因此还需要判断是否是第一个。对C#这个特点有兴趣的可以看看http://topic.csdn.net/u/20110805/16/d1a4226c-68d4-44be-ba65-b56a1614c942.html。
基本上到这里关于lambda表达式转换的基本知识都讲完了,基于这些的基础更进一步就是如何把LINQ转换成表达式,也就是说用手工代码把LINQ的查询语法糖解析成表达式,当然提供下载的代码里已经实现了这个,下次就是要讲讲其工作原理。
- lambda表达式的解析(八) 泛型调用及typeof操作
- lambda表达式的解析(一) 序
- 对lambda表达式的解析(一)
- 对lambda表达式的解析(二)
- lambda表达式的解析(二) 常量表达式
- lambda表达式的解析(三) 类型转换表达式
- lambda表达式的解析(四) 运算符表达式
- lambda表达式的解析(六) 成员访问表达式
- lambda表达式及Stream语法解析
- Kotlin笔记(八)Lambda表达式
- lambda表达式的解析(五) Lambda表达式与闭包类型
- 泛型约束及lambda表达式,表达式树
- 泛型约束及lambda表达式,表达式树
- lambda表达式的解析(七) 对象的创建
- lambda 表达式解析
- Lambda表达式 解析应用
- Lambda 表达式的简介及形成过程
- Kotlin高阶函数及Lambda表达式解析
- 设计模式 Factory Method
- 原码 补码 反码
- asp Array sort
- J2ME读取本地文本文件和Web上文本文件与图片的用法(汇总)
- 在PL/SQL中如何分割字符串(Split String)
- lambda表达式的解析(八) 泛型调用及typeof操作
- 一个程序员的爱情故事
- 笑话---看完 就大笑有益身心哦!!
- 用gSOAP开发Web Service程序
- qml 请求网络数据
- ARM汇编指令集
- iphone开发 设置view呈圆角
- setLatestEventInfo
- 在长官的面前尽量装傻一点