您的位置:首页 > 其它

(转)lambda表达式的解析(六) 成员访问表达式

2011-10-13 22:48 344 查看
成员访问的解析稍微有点复杂,从字符串角度看,访问一个实例的成员有三种形式:

访问成员字段或属性 instance.field instance.property

访问索引器 instance[]

访问方法 instance.method(...)

在解析的时候就按这三种形式进行解析,目前由于grammar修改的不完美所以还不支持显示进行泛型方法的调用。

view plaincopy to clipboardprint?

private Expression ProcessMemberAccessExpression(ParseTreeNode expNode)

{

Expression self = null;

ParseTreeNode args;

List<Expression> arglist;

var identifier = expNode.GetDescendant("Identifier");

var members = expNode.LastChild;

var variableName = identifier.GetValue();

var parameter = _parameters.Count > 0 ? _parameters.Peek().FirstOrDefault(p => p.Name == variableName) : null;

if (parameter != null)

{

self = parameter;

}

else

{

var pair = _knownVariables.FirstOrDefault(p => p.Key == variableName);

if (pair.Key == variableName)

{

self = Expression.Constant(pair.Value);

//self = Expression.Variable(pair.Value.GetType(), variableName);

}

else if (_parameters.Count > 0)

{

var parameters = _parameters.Peek();

var usedParameter = parameters.FirstOrDefault(p => p.Type.GetMember(variableName).Length > 0);

if (usedParameter != null)

self = Expression.MakeMemberAccess(usedParameter, usedParameter.Type.GetMember(variableName).First());

}

if (self == null)

{

throw new Exception(variableName);

}

}

if (members.ChildNodes.Count == 0)

{

return self;

}

foreach (var child in members.ChildNodes)

{

var type = self.Type;

var member = child.LastChild;

MemberInfo membinfo;

switch (member.GetName())

{

case "Identifier":

membinfo = type.GetMember(member.GetValue()).First();

self = Expression.MakeMemberAccess(self, membinfo);

break;

case "member_invoke":

var methodName = member.FirstChild.GetValue();

var method = type.GetMethod(methodName);

args = member.GetDescendant("argument_list");

arglist = new List<Expression>();

if (args != null)

{

foreach (var arg in args.ChildNodes)

{

arglist.Add(ProcessExpression(arg.FirstChild));

}

}

if (method == null)

{

method = MakeMethod(methodName, new[] { self.GetElementType() }.Union(arglist.Select(arg => arg.Type)).ToArray());

self = Expression.Call(method, new[] { self }.Union(arglist));

}

else

{

self = Expression.Call(self, method, arglist);

}

break;

case "member_indexer":

var indexer = type.GetProperty(member.FirstChild.GetValue());

args = member.GetDescendant("expression_list");

arglist = new List<Expression>();

foreach (var arg in args.ChildNodes)

{

arglist.Add(ProcessExpression(arg.FirstChild));

}

self = Expression.MakeIndex(self, indexer, arglist);

break;

default:

throw new Exception(member.GetName());

}

}

return self;

}

view plaincopy to clipboardprint?

private static ConcurrentDictionary<string, MethodInfo> extensionMethods = new ConcurrentDictionary<string, MethodInfo>();

#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["from"] = typeof(Queryable).GetMember("SelectMany")[3] as MethodInfo;

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

private static MethodInfo MakeMethod(string methodName, params Type[] genericTypes)

{

var len = extensionMethods[methodName].GetGenericArguments().Length;

return extensionMethods[methodName].MakeGenericMethod(genericTypes.Take(len).ToArray());

}

private static ConcurrentDictionary<string, MethodInfo> extensionMethods = new ConcurrentDictionary<string, MethodInfo>();

#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["from"] = typeof(Queryable).GetMember("SelectMany")[3] as MethodInfo;
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

private static MethodInfo MakeMethod(string methodName, params Type[] genericTypes)
{
var len = extensionMethods[methodName].GetGenericArguments().Length;
return extensionMethods[methodName].MakeGenericMethod(genericTypes.Take(len).ToArray());
}


MakeMethod就是根据方法名和泛型列表返回相应的扩展方法,这里列出的方法都是针对linq做的,全都是泛型方法。

通过方法名和泛型列表获得一个扩展方法需要一些技巧:

view plaincopy to clipboardprint?

internal static class TypeExtensions

{

private class ParameterComparer : IEqualityComparer<Type>

{

#region IEqualityComparer<Type> Members

public bool Equals(Type x, Type y)

{

if (x.IsGenericParameter && y.IsGenericParameter)

return true;

if (x.IsGenericType && y.IsGenericType)

{

if (x.Name != y.Name) return false;

if (x.BaseType != y.BaseType) return false;

var xa = x.GetGenericArguments();

var ya = y.GetGenericArguments();

if (xa.Length != ya.Length) return false;

var ret = xa.SequenceEqual(ya, this);

return ret;

}

if (x.IsGenericType) return true;

if (!y.IsGenericType) return true;

return x.Equals(y);

}

public int GetHashCode(Type obj)

{

return obj.GetHashCode();

}

#endregion

}

public static MethodInfo GetExtensionMethod(this Type type, string name, params Type[] arguments)

{

var query = from method in type.GetMethods()

let parameters = from p in method.GetParameters() select p.ParameterType

where method.Name == name

where method.IsDefined(typeof(ExtensionAttribute), false)

where parameters.SequenceEqual(arguments, new ParameterComparer())

select method;

return query.FirstOrDefault();

}

}

internal static class TypeExtensions
{
private class ParameterComparer : IEqualityComparer<Type>
{

#region IEqualityComparer<Type> Members

public bool Equals(Type x, Type y)
{
if (x.IsGenericParameter && y.IsGenericParameter)
return true;

if (x.IsGenericType && y.IsGenericType)
{
if (x.Name != y.Name) return false;
if (x.BaseType != y.BaseType) return false;

var xa = x.GetGenericArguments();
var ya = y.GetGenericArguments();
if (xa.Length != ya.Length) return false;

var ret = xa.SequenceEqual(ya, this);
return ret;
}

if (x.IsGenericType) return true;
if (!y.IsGenericType) return true;

return x.Equals(y);
}

public int GetHashCode(Type obj)
{
return obj.GetHashCode();
}

#endregion
}

public static MethodInfo GetExtensionMethod(this Type type, string name, params Type[] arguments)
{
var query = from method in type.GetMethods()
let parameters = from p in method.GetParameters() select p.ParameterType
where method.Name == name
where method.IsDefined(typeof(ExtensionAttribute), false)
where parameters.SequenceEqual(arguments, new ParameterComparer())
select method;

return query.FirstOrDefault();
}
}

简单点说就是通过反射获得扩展方法类下的所有方法,然后先按照名字匹配到一组方法,接着根据泛型参数来比较获得特定的那个,这里有个小的问题没解决,所以在实现IEqualityComparer<T>时代码比较冗余。小问题是

Func<T> 的泛型类型可以通过 typeof(Func<>)得到

而Func<T1,T2>泛型类型则是 typeof(Func<,>)

那么Func<T1,IEnumerable<T2>,T3>这种泛型类型如何获得? typeof(Func<,,>)无法匹配 而typeof(Func<,IEnumerable<>,>)无法通过编译。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: