您的位置:首页 > 其它

(转)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();

}

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的查询语法糖解析成表达式,当然提供下载的代码里已经实现了这个,下次就是要讲讲其工作原理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: