表达式解析器添加dynamic访问及静态方法调用
来源:互联网 发布:linux vi 退出不保存 编辑:程序博客网 时间:2024/06/08 16:28
最近碰到需要对一个匿名类的成员进行动态访问,从lambda上看就是类似
Func<dynamic, object> f = o => o.Company
这样的操作
之前的解析器无法正常解析成表达式,因为o是object,通过反射没法得到Company,需要修改ProcessMemberAccessExpression这个方法来支持dynamic object,片段:
if (type == typeof(object)) //Dynamic { var binder = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, member.GetValue(), type, new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); self = Expression.Dynamic(binder, type, self); }
目前只对property/field的访问支持dyanmic,method和indexer都没添加支持,如果谁有需求可以自行修改添加。
还有一个需求就是需要调用静态方法,类似
Func<dynamic, bool> f = o => String.IsNullOrEmpty(o.Company)
之前的解析器也没法正常工作,因为String被认为是一个变量,对静态方法支持也需要修改ProcessMemberAccessExpression这个方法。
先添加了一个With方法
public ExpressionParser With(Type type) { knownTypes.TryAdd(type.Name, type); return this; }
把需要调用静态方法的类先注册好,然后在ProcessMemberAccessExpression内
if (self == null) type = knownTypes.ContainsKey(variableName) ? knownTypes[variableName] : Type.GetType(variableName) ?? Type.GetType("System." + variableName); else type = self.Type;
由于self应该是变量或者常量,如果都没有,则判断为引用了一个类型,这样就能在接下来的调用中正确执行了。
完整的ProcessMemberAccessExpression代码:
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 (members.ChildNodes.Count == 0) { if (self == null) throw new Exception(variableName); return self; } foreach (var child in members.ChildNodes) { Type type; if (self == null) type = knownTypes.ContainsKey(variableName) ? knownTypes[variableName] : Type.GetType(variableName) ?? Type.GetType("System." + variableName); else type = self.Type; if (type == null) throw new Exception(variableName); var member = child.LastChild; MemberInfo membinfo; switch (member.GetName()) { case "Identifier": if (type == typeof(object)) //Dynamic { var binder = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, member.GetValue(), type, new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); self = Expression.Dynamic(binder, type, self); } else { 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 { var parameters = method.GetParameters(); for (int i = 0; i < parameters.Length; ++i) { if (parameters[i].ParameterType != arglist[i].Type) { arglist[i] = ConvertType(arglist[i], parameters[i].ParameterType); } } 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; }
完整代码下载:
http://tinynetevent.googlecode.com/files/ExpressionParser1207.zip
- 表达式解析器添加dynamic访问及静态方法调用
- 静态成员变量及方法的调用
- 静态成员变量及方法的调用
- 静态方法调用dll函数及类
- ognl表达式访问普通属性和静态方法
- Struts2 如何使用OGNL表达式访问静态方法和属性
- Struts2中使用OGNL调用静态方法及静态属性
- Struts 访问静态方法
- DLL(Dynamic Link Libraries)及调用约定
- VS2005环境下生成静态lib库及调用方法
- VS2005环境下生成静态lib库及调用方法
- VS 环境下生成静态lib库及调用方法
- C++ 编写DLL 动态及静态调用DLL方法
- 动态及静态的调用Action中的方法
- VS2005环境下生成静态lib库及调用方法
- C++静态库与动态库、创建及调用方法
- C#中静态方法和非静态方法的定义及调用
- 动态方法解析(Dynamic Method Resolution)
- strcat 的实现
- 必备的实用jquery代码段
- JVM总结(1)----JVM体系结构
- 解决error C2011: 'fd_set' : 'struct' type redefinition的方法
- Android在终端本地保存txt文本文件及zip文件
- 表达式解析器添加dynamic访问及静态方法调用
- [jbpm]jBPM(八): 也说jBPM + Tomcat + MySQL
- UITextField
- C语言基础-运算符优先级
- [jbpm]jBPM(九):jBPM的webSale在Tomcat下怎么连上的数据库?
- GBK UTF8 ANSI UNICODE 互转
- SQL Server 2008 通过配置数据库邮件实现发送邮件功能
- [jbpm]jBPM(十):webSale的"页面流"介绍
- ubuntu下网络抓包工具wireshark的使用