(转)lambda表达式的解析(八) 泛型调用及typeof操作
2011-10-13 22:50
363 查看
这篇是这个系列的最后一篇了,对于BlockExpression不再深入展开了,只对之前的泛型调用支持及typeof操作补漏。这次是进一步完善了grammar,现在能正常解析泛型调用及typeof操作,这使得我们能对这2种表达式进行正确的转换了。大家可以从http://tinynetevent.googlecode.com/files/ExpressionParser0809.zip下载到最新的代码。
由于对grammar作了一点修正,所以之前PareeTreeNode的扩展方法GetClrType也需要跟着改了:
view plaincopy to clipboardprint?
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();
}
至于typeof操作则略有不同,首先typeof是在静态编译时就确定的值,所以可以看做一个ConstantExpression。然后typeof操作可以获得带泛型参数的泛型类型,也就是可以typeof(Func<,>),所以解析的时候针对泛型需要两种方式都支持。typeof视为一元运算符,解析的入口为之前介绍的一元运算符处理方法:
view plaincopy to clipboardprint?
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(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的查询语法糖解析成表达式,当然提供下载的代码里已经实现了这个,下次就是要讲讲其工作原理。
由于对grammar作了一点修正,所以之前PareeTreeNode的扩展方法GetClrType也需要跟着改了:
view plaincopy to clipboardprint?
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();
}
view plaincopy to clipboardprint? case "member_invoke": var methodName = member.FirstChild.GetValue(); var method = type.GetMethod(methodName); var targs = member.GetGenericArguments(); if (targs != null) { method = method.MakeGenericMethod(targs); } 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视为一元运算符,解析的入口为之前介绍的一元运算符处理方法:
view plaincopy to clipboardprint?
private Expression ProcessUnaryExpression(ParseTreeNode expNode)
{
string op;
var first = expNode.FirstChild;
var second = expNode.LastChild;
switch (first.GetName())
{
....
case "typeof_expression":
return ProcessTypeofExpression(first);
....
}
view plaincopy to clipboardprint? 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); } 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操作
- [012]泛型--lambda表达式捕获
- asp.net Linq和泛型,IEnumerable和IQueryable之间的区别,Lambda表达式,Linq to Sql停止开发转为 Entity Framework
- JAVA 8 StreamAPI 和 lambda表达式 总结(四)--stream的一些聚合操作
- 泛型委托及委托中所涉及到匿名方法、Lambda表达式
- Python中 Lambda表达式全面解析
- lambda表达式及Stream语法解析
- (转)lambda表达式的解析(一) 序
- 在Java 8中对stream带有lambda表达式的操作进行调试
- c#隐藏函数 lambda表达式 泛型综合使用代码
- C++中的数组array和vector,lambda表达式,C字符串加操作,C++中新类型数组(数组缓存),多元数组,new缓冲
- Kotlin高阶函数及Lambda表达式解析
- Java_SE02-04-正则表达式,包装类,日期操作,泛型,集合框架
- Java1.8新特性关于lambda表达式与Stream流的使用以及对集合的实用操作
- 方法的直接调用,反射调用与……Lambda表达式调用
- (转)lambda表达式的解析(二) 常量表达式
- C++11 lambda 表达式解析
- python的字符串和对象的一些操作和运算以及lambda表达式
- JDK 8 Lambda 表达式解析Map和List
- lambda表达式的解析(四) 运算符表达式