最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html
关于我和表达式树其实我也没有深入了解表达式树一些内在实现的原理,所以具体来说它到底是个什么东西我也不是很清楚,我的理解只是他是可以将'部分'委托构造成对象,方便我们对他进行解析; 虽然我没有完全搞懂表达式树,但这并不妨碍我使用它(如果以后有时间,我想我会更深入的去和它接触一下)
Lamda + 表达式树的性能瓶颈对于Lamda表达式树我的感觉是又爱又恨
书写和阅读方面,无疑是非常成功的,他大大的减少了书写难度,增加了可读性
但另一方面,在程序的性能上又是如此的糟糕
来看下面一个栗子:
staticvoidMain()
{
Where1(u=> u.Name =="1");
Where2(u=> u.Name =="1");
}publicstaticvoidWhere1(ExPRession<Func<User,bool>>expr)
{
}publicstaticvoidWhere2(Func<User,bool>expr)
{
}
栗子中的 Where1 和 Where2 两个方法,唯一的不同,一个是委托,一个是表达式树
同样运行Where1和Where2 一万次,Where2是0ms,Where1是57ms
也就是说从Func<User, bool>转为Expression<Func<User, bool>>一万次需要57ms
这对于我这样一个追求性能的人来说,实在是有点难受!
到不至于不能接受,只有有点难受
但从另一方面我也在考虑,为什么像这样的lamda不能直接预编译成Expression呢?期待微软的优化吧~
伪框架为什么我的标题中的框架为带有引号?
因为我觉得这其实是一个伪框架
但他确实能帮助我们更好的解析Expression对象,或许应该把他称之为解决方案或是别的
不过~管他呢!能用就行了
你应该了解的Expression刚才说了虽然我也没有完全搞懂,但是有些东西还是应该知道的
比如:
以Expression作为基类的子类一共有多少个他们分别是干什么的第一个问题比较简单
现在在vs中敲下System.Linq.Expressions.Expression然后按F1如果顺利的话,你现在已经打开了"MSDN"如果没有的话就手动点一下吧然后滚动到屏幕最下面
好了这里看到的就是所有`public`的子类(其实没有公开的还有更多)
至于他们分别是干什么用的,每一个都有自己不同的用法,这里不可能一一说明了,下面的内容也只会涉及到一部分,其他就要自己慢慢研究了
举个栗子:
BinaryExpression ----表示包含二元运算符的表达式最基础的用法就是它的三个属性Left ,Right ,NodeType
Left获取二元运算的左操作数。
Right获取二元运算的右操作数。
NodeType获取此 Expression 的节点类型。
如it = it.Name == "blqw"就是一个BinaryExpression
Left = it.Name
Right = "blqw"
NodeType = Equals
大概就是这么一个意思吧
效果预览
框架结构嗯.允许我还是叫他框架吧,毕竟听上去比较高端大气上档次啊
暂时是这样
Parsers文件夹里面的是具体对应每一种表达式树的解析的具体实现ExpressionParser 表达式树解析器抽象基类,实现IExpressionParserExpressionTypeCode 枚举,枚举了所有的类型的表达式树IExpressionParser表达式树解析器接口Parser调用解析器的静态对象,也可以看作入口或工厂,根据表达式树类型调用具体类ParserArgs解析器参数,在解析表达式树的方法中保持传递,可以保存解析中所使用的参数和保存解析结果代码publicclassParserArgs
{publicParserArgs()
{
Builder=newStringBuilder();
}publicStringBuilder Builder {get;privateset; }publicIList<ParameterExpression> Forms {get;set; }publicreadonlystring[] FormsAlias = {"it","A","B","C","D","E"};
}
ParserArgs
IExpressionParser
///<summary>表达式树解析接口///</summary>publicinterfaceIExpressionParser
{voidSelect(Expression expr, ParserArgs args);voidWhere(Expression expr, ParserArgs args);voidGroupBy(Expression expr, ParserArgs args);voidHaving(Expression expr, ParserArgs args);voidOrderBy(Expression expr, ParserArgs args);voidObject(Expression expr, ParserArgs args);
}
///<summary>表达式树解析抽象泛型类///</summary>publicabstractclassExpressionParser<T>: IExpressionParserwhereT : Expression
{publicabstractvoidSelect(T expr, ParserArgs args);publicabstractvoidWhere(T expr, ParserArgs args);publicabstractvoidGroupBy(T expr, ParserArgs args);publicabstractvoidHaving(T expr, ParserArgs args);publicabstractvoidOrderBy(T expr, ParserArgs args);publicabstractvoidObject(T expr, ParserArgs args);publicvoidSelect(Expression expr, ParserArgs args)
{
Select((T)expr, args);
}publicvoidWhere(Expression expr, ParserArgs args)
{
Where((T)expr, args);
}publicvoidGroupBy(Expression expr, ParserArgs args)
{
GroupBy((T)expr, args);
}publicvoidHaving(Expression expr, ParserArgs args)
{
Having((T)expr, args);
}publicvoidOrderBy(Expression expr, ParserArgs args)
{
OrderBy((T)expr, args);
}publicvoidObject(Expression expr, ParserArgs args)
{
Object((T)expr, args);
}
}
ExpressionParser
///<summary>表达式类型枚举///</summary>publicenumExpressionTypeCode
{///<summary>未知类型表达式///</summary>Unknown =0,///<summary>空表达式 null///</summary>Null =1,///<summary>表示包含二元运算符的表达式。///</summary>BinaryExpression =2,///<summary>表示一个包含可在其中定义变量的表达式序列的块。///</summary>BlockExpression =3,///<summary>表示包含条件运算符的表达式。///</summary>ConditionalExpression =4,///<summary>表示具有常量值的表达式。///</summary>ConstantExpression =5,///<summary>发出或清除调试信息的序列点。 这允许调试器在调试时突出显示正确的源代码。///</summary>DebugInfoExpression =6,///<summary>表示类型或空表达式的默认值。///</summary>DefaultExpression =7,///<summary>表示动态操作。///</summary>DynamicExpression =8,///<summary>表示无条件跳转。 这包括 return 语句、break 和 continue 语句以及其他跳转。///</summary>GotoExpression =9,///<summary>表示编制属性或数组的索引。///</summary>IndexExpression =10,///<summary>表示将委托或 lambda 表达式应用于参数表达式列表的表达式。///</summary>InvocationExpression =11,///<summary>表示一个标签,可以将该标签放置在任何 Expression 上下文中。///</summary>LabelExpression =12,///<summary>描述一个 lambda 表达式。 这将捕获与 .NET 方法体类似的代码块。///</summary>LambdaExpression =13,///<summary>表示包含集合初始值设定项的构造函数调用。///</summary>ListInitExpression =14,///<summary>表示无限循环。 可以使用“break”退出它。///</summary>LoopExpression =15,///<summary>表示访问字段或属性。///</summary>MemberExpression =16,///<summary>表示调用构造函数并初始化新对象的一个或多个成员。///</summary>MemberInitExpression =17,///<summary>表示对静态方法或实例方法的调用。///</summary>MethodCallExpression =18,///<summary>表示创建新数组并可能初始化该新数组的元素。///</summary>NewArrayExpression =19,///<summary>表示构造函数调用。///</summary>NewExpression =20,///<summary>表示命名的参数表达式。///</summary>ParameterExpression =21,///<summary>一个为变量提供运行时读/写权限的表达式。///</summary>RuntimeVariablesExpression =22,///<summary>表示一个控制表达式,该表达式通过将控制传递到 SwitchCase 来处理多重选择。///</summary>SwitchExpression =23,///<summary>表示 try/catch/finally/fault 块。///</summary>TryExpression =24,///<summary>表示表达式和类型之间的操作。///</summary>TypeBinaryExpression =25,///<summary>表示包含一元运算符的表达式。///</summary>UnaryExpression =26,
}
ExpressionTypeCode
///<summary>解析器静态对象///</summary>publicstaticclassParser
{privatestaticreadonlyIExpressionParser[] Parsers =InitParsers();staticIExpressionParser[] InitParsers()
{varcodes = Enum.GetValues(typeof(ExpressionTypeCode));varparsers =newIExpressionParser[codes.Length];foreach(ExpressionTypeCode codeincodes)
{if(code.ToString().EndsWith("Expression"))
{vartype = Type.GetType(typeof(Parser).Namespace +"."+ code.ToString() +"Parser");if(type !=null)
{
parsers[(int)code] =(IExpressionParser)Activator.CreateInstance(type);
}
}
}returnparsers;
}///<summary>得到表达式类型的枚举对象</summary>///<param name="expr">扩展对象:Expression</param>///<returns></returns>publicstaticExpressionTypeCode GetCodeType(Expression expr)
{if(expr ==null)
{returnExpressionTypeCode.Null;
}if(exprisBinaryExpression)
{returnExpressionTypeCode.BinaryExpression;
}if(exprisBlockExpression)
{returnExpressionTypeCode.BlockExpression;
}if(exprisConditionalExpression)
{returnExpressionTypeCode.ConditionalExpression;
}if(exprisConstantExpression)
{returnExpressionTypeCode.ConstantExpression;
}if(exprisDebugInfoExpression)
{returnExpressionTypeCode.DebugInfoExpression;
}if(exprisDefaultExpression)
{returnExpressionTypeCode.DefaultExpression;
}if(exprisDynamicExpression)
{returnExpressionTypeCode.DynamicExpression;
}if(exprisGotoExpression)
{returnExpressionTypeCode.GotoExpression;
}if(exprisIndexExpression)
{returnExpressionTypeCode.IndexExpression;
}if(exprisInvocationExpression)
{returnExpressionTypeCode.InvocationExpression;
}if(exprisLabelExpression)
{returnExpressionTypeCode.LabelExpression;
}if(exprisLambdaExpression)
{returnExpressionTypeCode.LambdaExpression;
}if(exprisListInitExpression)
{returnExpressionTypeCode.ListInitExpression;
}if(exprisLoopExpression)
{returnExpressionTypeCode.LoopExpression;
}if(exprisMemberExpression)
{returnExpressionTypeCode.MemberExpression;
}if(exprisMemberInitExpression)
{returnExpressionTypeCode.MemberInitExpression;
}if(exprisMethodCallExpression)
{returnExpressionTypeCode.MethodCallExpression;
}if(exprisNewArrayExpression)
{returnExpressionTypeCode.NewArrayExpression;
}if(exprisNewExpression)
{returnExpressionTypeCode.NewArrayExpression;
}if(exprisParameterExpression)
{returnExpressionTypeCode.ParameterExpression;
}if(exprisRuntimeVariablesExpression)
{returnExpressionTypeCode.RuntimeVariablesExpression;
}if(exprisSwitchExpression)
{returnExpressionTypeCode.SwitchExpression;
}if(exprisTryExpression)
{returnExpressionTypeCode.TryExpression;
}if(exprisTypeBinaryExpression)
{returnExpressionTypeCode.TypeBinaryExpression;
}if(exprisUnaryExpression)
{returnExpressionTypeCode.UnaryExpression;
}returnExpressionTypeCode.Unknown;
}///<summary>得到当前表达式对象的解析组件</summary>///<param name="expr">扩展对象:Expression</param>///<returns></returns>publicstaticIExpressionParser GetParser(Expression expr)
{varcodetype =GetCodeType(expr);varparser = Parsers[(int)codetype];if(parser ==null)
{switch(codetype)
{caseExpressionTypeCode.Unknown:thrownewArgumentException("未知的表达式类型","expr");caseExpressionTypeCode.Null:thrownewArgumentNullException("expr","表达式为空");default:thrownewNotImplementedException("尚未实现"+ codetype +"的解析");
}
}returnparser;
}publicstaticvoidSelect(Expression expr, ParserArgs args)
{
GetParser(expr).Select(expr, args);
}publicstaticvoidWhere(Expression expr, ParserArgs args)
{
GetParser(expr).Where(expr, args);
}publicstaticvoidGroupBy(Expression expr, ParserArgs args)
{
GetParser(expr).GroupBy(expr, args);
}publicstaticvoidHaving(Expression expr, ParserArgs args)
{
GetParser(expr).Having(expr, args);
}publicstaticvoidOrderBy(Expression expr, ParserArgs args)
{
GetParser(expr).OrderBy(expr, args);
}publicstaticvoidObject(Expression expr, ParserArgs args)
{
GetParser(expr).Object(expr, args);
}
}
Parser
原理分解首先将所有类型的表达式树以枚举的形式表现出来,1来是为了更直观便于2是为了给他们编号
有了编号就可以方便的在数组或集合中给他们安排位置了
初始化在Parser类中,放置一个静态字段
privatestaticreadonlyIExpressionParser[] Parsers = InitParsers();
在InitParsers方法中,使用反射查找当前命名空间下名称为枚举名 + Parser 的类,如果有则实例化,并根据枚举的值,在集合中保存
ps:枚举名 + Parser 作为解析器的命名规则,仅仅是为了方便反射调用,Parsers[0] = new xxx() 这个依然是可以由后期调用绑定的
调用然后提供一个方法,用于获取当前表达式对象对应的枚举值
publicstaticExpressionTypeCodeGetCodeType(Expressionexpr)
{if(expr ==null)
{returnExpressionTypeCode.Null;
}if(exprisBinaryExpression)
{returnExpressionTypeCode.BinaryExpression;
}if(exprisBlockExpression)
{returnExpressionTypeCode.BlockExpression;
}
...
...returnExpressionTypeCode.Unknown;
}
这里的方法我没有选择用反射来获取枚举值,还是基于对性能的考虑,这样测试快5~10倍,有兴趣的可以测试一下
publicstaticExpressionTypeCode GetCodeType(Expression expr)
{if(expr ==null)
{returnExpressionTypeCode.Null;
}
ExpressionTypeCode tc;if(Enum.TryParse(expr.GetType().Name,outtc))
{returntc;
}returnExpressionTypeCode.Unknown;
}
反射代码
得到枚举之后,就可以按枚举的值,从集合中获取已经实例化的解析器为了方便调用,写了一个方法GetParser
publicstaticIExpressionParser GetParser(Expressionexpr)
{varcodetype =GetCodeType(expr);varparser = Parsers[(int)codetype];if(parser ==null)
{switch(codetype)
{caseExpressionTypeCode.Unknown:thrownewArgumentException("未知的表达式类型","expr");caseExpressionTypeCode.Null:thrownewArgumentNullException("expr","表达式为空");default:thrownewNotImplementedException("尚未实现"+ codetype +"的解析");
}
}returnparser;
}
得到解析器之后,就可以做爱做的事了,
好了我也有点累了,先这样吧
未完待续...干货!表达式树解析"框架"(2)
干货!表达式树解析"框架"(3)