揭示表达式树的隐衷面纱
【转】再讲IQueryable<T>,揭示表明式树的私人民居房面纱
接上篇《先说IEnumerable,大家每日用的foreach你真的懂它吗?》
接上篇《先说IEnumerable,大家每一日用的foreach你真的懂它吗?》
不久前园子里定制本身的orm那是四个风生水起,认为不整个本人的orm都倒霉意思继续混和讯了(开个玩笑)。那么从前大家有须要细心领会下 IQueryable<T> ,于是就有了此文。
日前园子里定制自身的orm那是二个风生水起,感到不整个本身的orm都倒霉意思继续混天涯论坛了(开个玩笑)。那么以前大家有要求稳重精通下 IQueryable<T> ,于是就有了此文。
怎样是树?
哪些是树?这一个难点好像有个别白痴。树不便是树嘛。看图:
咱俩从最上边包车型地铁中坚发轫往上看,主枝-分支-分支….能够说是极端分支下去。大家倒过来看就是如此:
日常我们用得最多的树结构数据就是XML了,节点上面能够Infiniti加多子节点。大家思索日常还用过哪些树结构数据,比方:食谱Infiniti分级、商讨区的楼层。
那和我们后天讲的有毛关系啊。… 大家明天重要正是来深入分析表明式树的。、
lambda表达式和表明式树的区分:
Lambda表达式:
Func<Student, bool> func = t => t.Name == "农码一生";
表达式树:
Expression<Func<Student, bool>> expression = t => t.Name == "农码一生";
咋一看,没啥区别啊。表明式只是用Expression包了一下而已。那您错了,这只是Microsoft给大家来得的障眼法,我们看编写翻译后的C#代码:
先是个lambda表达式编译成了无名氏函数,第1个表明式树编写翻译成一了一群大家不认得的东西,远比大家原来写的lambda复杂得多。
结论:
- 作者们平素应用的表明式树,是编辑的lambda表明式然后编写翻译成的表明式树,也就是说平日相像景色采用的表明式树都是编写翻译器帮大家完结的。(当然,大家得以能够手动的积极的去创表达式树。只是太辛勤,不是必得景况并没有什么人愿意去干这一个苦活呢)
大家来拜望表明式树到底有如何奇妙的地方:
有未有看出点认为来?Body里面有Right、Left,Right里面又有Right、Left,它们的项目都以继续自 Expression 。这种节点上边有节点,能够无限叠加下去的数据结构大家誉为树结构数据。也正是大家的表达式树。
补:上面的 Student 实体类:
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public string Sex { get; set; }
}
View Code
怎么是树?
如何是树?那些难点好像有一些白痴。树不就是树嘛。看图:
我们从最下边的主导初步往上看,主枝-分支-分支….能够说是极其分支下去。我们倒过来看正是那般:
平时大家用得最多的树结构数据就是XML了,节点下边能够特别增添子节点。我们思念经常还用过怎么样树结构数据,举例:美食做法Infiniti分级、商量区的楼层。
那和大家今日讲的有毛关系啊。… 大家今日重要正是来深入分析说明式树的。、
lambda表达式和公布式树的差别:
Lambda表达式:
Func<Student, bool> func = t => t.Name == "农码一生";
表明式树:
Expression<Func<Student, bool>> expression = t => t.Name == "农码一生";
咋一看,没啥分裂啊。表明式只是用Expression包了一下罢了。那你错了,那只是Microsoft给我们体现的障眼法,我们看编写翻译后的C#代码:
首先个lambda表明式编译成了无名氏函数,第2个表达式树编写翻译成一了一群大家不认知的事物,远比大家原来写的lambda复杂得多。
结论:
- 咱俩平昔利用的表达式树,是编写制定的lambda表明式然后编写翻译成的表明式树,也正是说平日相像情状使用的表明式树都是编译器帮大家成功的。(当然,大家得以能够手动的主动的去创表达式树。只是太费事,不是必备情状并未有何人愿意去干这一个苦活呢)
大家来走访表明式树到底有如何神奇的地方:
有未有看出点以为来?Body里面有Right、Left,Right里面又有Right、Left,它们的系列都以承接自 Expression 。这种节点上边有节点,能够极度叠合下去的数据结构大家誉为树结构数据。也便是大家的表达式树。
补:上面的 Student 实体类:
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public string Sex { get; set; }
}
View Code
解析表明式树
地点大家来看了所谓的表明式树,其余也从未想像的那么复杂嘛。不正是贰个树结构数据嘛。假若大家要落成和煦的orm,免不了要剖判表明式树。一般提及分析树结构数据都会用到递归算法。上面我们起首深入分析表达式树。
先定义深入分析方法:
//表达式解析
public static class AnalysisExpression
{
public static void VisitExpression(Expression expression)
{
switch (expression.NodeType)
{
case ExpressionType.Call://执行方法
MethodCallExpression method = expression as MethodCallExpression;
Console.WriteLine("方法名:" + method.Method.Name);
for (int i = 0; i < method.Arguments.Count; i++)
VisitExpression(method.Arguments[i]);
break;
case ExpressionType.Lambda://lambda表达式
LambdaExpression lambda = expression as LambdaExpression;
VisitExpression(lambda.Body);
break;
case ExpressionType.Equal://相等比较
case ExpressionType.AndAlso://and条件运算
BinaryExpression binary = expression as BinaryExpression;
Console.WriteLine("运算符:" + expression.NodeType.ToString());
VisitExpression(binary.Left);
VisitExpression(binary.Right);
break;
case ExpressionType.Constant://常量值
ConstantExpression constant = expression as ConstantExpression;
Console.WriteLine("常量值:" + constant.Value.ToString());
break;
case ExpressionType.MemberAccess:
MemberExpression Member = expression as MemberExpression;
Console.WriteLine("字段名称:{0},类型:{1}", Member.Member.Name, Member.Type.ToString());
break;
default:
Console.Write("UnKnow");
break;
}
}
}
调用剖析方法:
Expression<Func<Student, bool>> expression = t => t.Name == "农码一生" && t.Sex == "男";
AnalysisExpression.VisitExpression(expression);
作者们来探视试行进程:
一层一层的往子节点递归,直到遍历完全数的节点。最终打字与印刷效果如下:
基本上大家想要的成分和值都取到了,接着怎么组装就看你和睦的心怀了。是拼成sql,依然生成url,请随便!
剖析表明式树
地点大家看出了所谓的表达式树,其余也平昔不想象的那么复杂嘛。不就是二个树结构数据嘛。倘若我们要兑现自个儿的orm,免不了要深入分析表达式树。一般谈到深入分析树结构数据都会用到递归算法。下边大家起首分析表明式树。
先定义深入分析方法:
//表达式解析
public static class AnalysisExpression
{
public static void VisitExpression(Expression expression)
{
switch (expression.NodeType)
{
case ExpressionType.Call://执行方法
MethodCallExpression method = expression as MethodCallExpression;
Console.WriteLine("方法名:" + method.Method.Name);
for (int i = 0; i < method.Arguments.Count; i++)
VisitExpression(method.Arguments[i]);
break;
case ExpressionType.Lambda://lambda表达式
LambdaExpression lambda = expression as LambdaExpression;
VisitExpression(lambda.Body);
break;
case ExpressionType.Equal://相等比较
case ExpressionType.AndAlso://and条件运算
BinaryExpression binary = expression as BinaryExpression;
Console.WriteLine("运算符:" + expression.NodeType.ToString());
VisitExpression(binary.Left);
VisitExpression(binary.Right);
break;
case ExpressionType.Constant://常量值
ConstantExpression constant = expression as ConstantExpression;
Console.WriteLine("常量值:" + constant.Value.ToString());
break;
case ExpressionType.MemberAccess:
MemberExpression Member = expression as MemberExpression;
Console.WriteLine("字段名称:{0},类型:{1}", Member.Member.Name, Member.Type.ToString());
break;
default:
Console.Write("UnKnow");
break;
}
}
}
调用分析方法:
Expression<Func<Student, bool>> expression = t => t.Name == "农码一生" && t.Sex == "男";
AnalysisExpression.VisitExpression(expression);
我们来拜谒实践进度:
一层一层的往子节点递归,直到遍历完全部的节点。最终打字与印刷效果如下:
比很多我们想要的成分和值都取到了,接着怎么组装就看你协和的心情了。是拼成sql,还是生成url,请随便!
福寿齐天团结的IQueryable<T>、IQueryProvider
唯有分析了表明式树就能够鼓捣自身的orm了?不行,起码也要依据 IQueryable<T> 接口来编码吧。
接着大家自定义个类 MyQueryable<T> 继承接口 IQueryable<T> :
public class MyQueryable<T> : IQueryable<T>
{
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
public Type ElementType
{
get { throw new NotImplementedException(); }
}
public Expression Expression
{
get { throw new NotImplementedException(); }
}
public IQueryProvider Provider
{
get { throw new NotImplementedException(); }
}
}
咱俩见到个中有个接口属性 IQueryProvider ,这些接口的成效大着吧,首要效能是在奉行查询操作符的时候再度成立 IQueryable<T> 并且最终遍历的时候推行sql远程取值。我们还看见了 Expression 属性。
今昔大家知晓了 IQueryable<T> 和 Expression (表明式树)的关联了吧:
- IQueryable<T> 最入眼的意义正是用来囤积 Expression(表达式树)
下边大家也自定义现实了 IQueryProvider 接口的类 MyQueryProvider :
public class MyQueryProvider : IQueryProvider
{
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
throw new NotImplementedException();
}
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
throw new NotImplementedException();
}
public object Execute(Expression expression)
{
throw new NotImplementedException();
}
}
地方全都以自动生成的伪代码,上面大家来填充具体的兑现:
public class MyQueryProvider : IQueryProvider
{
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new MyQueryable<TElement>(expression);
}
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
return default(TResult);
}
public object Execute(Expression expression)
{
return new List<object>();
}
}
public class MyQueryable<T> : IQueryable<T>
{
public MyQueryable()
{
_provider = new MyQueryProvider();
_expression = Expression.Constant(this);
}
public MyQueryable(Expression expression)
{
_provider = new MyQueryProvider();
_expression = expression;
}
public Type ElementType
{
get { return typeof(T); }
}
private Expression _expression;
public Expression Expression
{
get { return _expression; }
}
private IQueryProvider _provider;
public IQueryProvider Provider
{
get { return _provider; }
}
public IEnumerator GetEnumerator()
{
return (Provider.Execute(Expression) as IEnumerable).GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
var result = _provider.Execute<List<T>>(_expression);
if (result == null)
yield break;
foreach (var item in result)
{
yield return item;
}
}
}
View Code
施行代码:
var aa = new MyQueryable<Student>();
var bb = aa.Where(t => t.Name == "农码一生");
var cc = bb.Where(t => t.Sex == "男");
var dd = cc.AsEnumerable();
var ee = cc.ToList();
跟着大家看看实行进度:
结论:
- 历次在施行 Where 查询操作符的时候 IQueryProvider 会为大家创造二个新的 IQueryable<T>
- 调用 AsEnumerable() 方法的时候并不会去实际取值(只是获得多少个IEnumerable)[留神:在EF里面查询不要先取IEnumerable后滤筛,因为AsEnumerable()会扭转查询全表的sql]
- 施行 ToList() 方法时才去真正调用迭代器 GetEnumerator() 取值
- 实在取值的时候,会去推行 IQueryProvider 中的 Execute 方法。(正是在调用那么些方式的时候分析表达式数,然后实行取得结果)
咱俩看到真的应该办实事的 Execute
我们却让她重回暗中认可值了。
当今估量有人不爽了,你到是有血有肉实现下 Execute 。好呢!(其实通过下边说的解析表达式树,你能够自身在此地做想做的别的事了。)
先是为了轻便起见,我们用多少个会面做为数据源:
//构造Student数组
public static List<Student> StudentArrary = new List<Student>()
{
new Student(){Name="农码一生", Age=26, Sex="男", Address="长沙"},
new Student(){Name="小明", Age=23, Sex="男", Address="岳阳"},
new Student(){Name="嗨-妹子", Age=25, Sex="女", Address="四川"}
};
接下来,重新写三个VisitExpression2主意:(和事先的区分:
现在指标是取表明式树中的表明式,并非重复构造建设成sql或别的)
public static void VisitExpression2(Expression expression, ref List<LambdaExpression> lambdaOut)
{
if (lambdaOut == null)
lambdaOut = new List<LambdaExpression>();
switch (expression.NodeType)
{
case ExpressionType.Call://执行方法
MethodCallExpression method = expression as MethodCallExpression;
Console.WriteLine("方法名:" + method.Method.Name);
for (int i = 0; i < method.Arguments.Count; i++)
VisitExpression2(method.Arguments[i], ref lambdaOut);
break;
case ExpressionType.Lambda://lambda表达式
LambdaExpression lambda = expression as LambdaExpression;
lambdaOut.Add(lambda);
VisitExpression2(lambda.Body, ref lambdaOut);
break;
case ExpressionType.Equal://相等比较
case ExpressionType.AndAlso://and条件运算
BinaryExpression binary = expression as BinaryExpression;
Console.WriteLine("运算符:" + expression.NodeType.ToString());
VisitExpression2(binary.Left, ref lambdaOut);
VisitExpression2(binary.Right, ref lambdaOut);
break;
case ExpressionType.Constant://常量值
ConstantExpression constant = expression as ConstantExpression;
Console.WriteLine("常量值:" + constant.Value.ToString());
break;
case ExpressionType.MemberAccess:
MemberExpression Member = expression as MemberExpression;
Console.WriteLine("字段名称:{0},类型:{1}", Member.Member.Name, Member.Type.ToString());
break;
case ExpressionType.Quote:
UnaryExpression Unary = expression as UnaryExpression;
VisitExpression2(Unary.Operand, ref lambdaOut);
break;
default:
Console.Write("UnKnow");
break;
}
}
下一场再次达成形式 Execute :
public TResult Execute<TResult>(Expression expression)
{
List<LambdaExpression> lambda = null;
AnalysisExpression.VisitExpression2(expression, ref lambda);//解析取得表达式数中的表达式
IEnumerable<Student> enumerable = null;
for (int i = 0; i < lambda.Count; i++)
{
//把LambdaExpression转成Expression<Func<Student, bool>>类型
//通过方法Compile()转成委托方法
Func<Student, bool> func = (lambda[i] as Expression<Func<Student, bool>>).Compile();
if (enumerable == null)
enumerable = Program.StudentArrary.Where(func);//取得IEnumerable
else
enumerable = enumerable.Where(func);
}
dynamic obj = enumerable.ToList();//(注意:这个方法的整个处理过程,你可以换成解析sql执行数据库查询,或者生成url然后请求获取数据。)
return (TResult)obj;
}
实施进度:
个人对 IQueryable 延迟加载的精晓:
- 前段部分的查询操作符只是把逻辑解释存入表明式树,并不曾远程实行sql。
- foreache实施的是 IEnumerable<T> ,然则 IEnumerable<T> 一样具备推迟加载的天性。每一回迭代的时候才真的的取多少。且在运用导航属性的时候会重新查询数据库。(下一次说延迟加载不要遗忘了 IEnumerable 的功绩哦!)
小知识:
表明式树转成Lambda表明式:
Expression<Func<Student, bool>> expression = t => t.Name == "农码一生";
Func<Student, bool> func = expression.Compile();
兑现自个儿的IQueryable<T>、IQueryProvider
只是分析了表达式树就能够鼓捣本身的orm了?不行,起码也要基于 IQueryable<T> 接口来编码吧。
继之大家自定义个类 MyQueryable<T> 承继继口 IQueryable<T> :
public class MyQueryable<T> : IQueryable<T>
{
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
public Type ElementType
{
get { throw new NotImplementedException(); }
}
public Expression Expression
{
get { throw new NotImplementedException(); }
}
public IQueryProvider Provider
{
get { throw new NotImplementedException(); }
}
}
大家看来里边有个接口属性 IQueryProvider ,那几个接口的功效大着啊,首要成效是在进行查询操作符的时候重新创造 IQueryable<T> 何况最终遍历的时候试行sql远程取值。大家还看见了 Expression 属性。
于今大家精晓了 IQueryable<T> 和 Expression (表明式树)的关系了吧:
- IQueryable<T> 最根本的意义就是用来积累 Expression(表明式树)
下边大家也自定义现实了 IQueryProvider 接口的类 MyQueryProvider :
public class MyQueryProvider : IQueryProvider
{
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
throw new NotImplementedException();
}
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
throw new NotImplementedException();
}
public object Execute(Expression expression)
{
throw new NotImplementedException();
}
}
上面全都以自动生成的伪代码,上边我们来填充具体的贯彻:
public class MyQueryProvider : IQueryProvider
{
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new MyQueryable<TElement>(expression);
}
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
return default(TResult);
}
public object Execute(Expression expression)
{
return new List<object>();
}
}
public class MyQueryable<T> : IQueryable<T>
{
public MyQueryable()
{
_provider = new MyQueryProvider();
_expression = Expression.Constant(this);
}
public MyQueryable(Expression expression)
{
_provider = new MyQueryProvider();
_expression = expression;
}
public Type ElementType
{
get { return typeof(T); }
}
private Expression _expression;
public Expression Expression
{
get { return _expression; }
}
private IQueryProvider _provider;
public IQueryProvider Provider
{
get { return _provider; }
}
public IEnumerator GetEnumerator()
{
return (Provider.Execute(Expression) as IEnumerable).GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
var result = _provider.Execute<List<T>>(_expression);
if (result == null)
yield break;
foreach (var item in result)
{
yield return item;
}
}
}
View Code
实践代码:
var aa = new MyQueryable<Student>();
var bb = aa.Where(t => t.Name == "农码一生");
var cc = bb.Where(t => t.Sex == "男");
var dd = cc.AsEnumerable();
var ee = cc.ToList();
继之我们看看实施进程:
结论:
- 老是在实施 Where 查询操作符的时候 IQueryProvider 会为我们成立一个新的 IQueryable<T>
- 调用 AsEnumerable() 方法的时候并不会去实际取值(只是得到多少个IEnumerable)[瞩目:在EF里面查询不要先取IEnumerable后滤筛,因为AsEnumerable()会变卦查询全表的sql]
- 实施 ToList() 方法时才去真正调用迭代器 GetEnumerator() 取值
- 实在取值的时候,会去推行 IQueryProvider 中的 Execute 方法。(就是在调用这一个方法的时候分析表达式数,然后施行获得结果)
大家看出确实应该办实事的 Execute
我们却让他重回暗中认可值了。
前段时间估量有人不爽了,你到是切实可行完毕下 Execute 。可以吗!(其实通过地点说的分析表明式树,你能够团结在此间做想做的别样事了。)
第一为了轻巧起见,大家用二个晤面做为数据源:
//构造Student数组
public static List<Student> StudentArrary = new List<Student>()
{
new Student(){Name="农码一生", Age=26, Sex="男", Address="长沙"},
new Student(){Name="小明", Age=23, Sex="男", Address="岳阳"},
new Student(){Name="嗨-妹子", Age=25, Sex="女", Address="四川"}
};
然后,重新写一个VisitExpression2格局:(和事先的区分:
未来指标是取表达式树中的表明式,实际不是双重创设成sql或别的)
public static void VisitExpression2(Expression expression, ref List<LambdaExpression> lambdaOut)
{
if (lambdaOut == null)
lambdaOut = new List<LambdaExpression>();
switch (expression.NodeType)
{
case ExpressionType.Call://执行方法
MethodCallExpression method = expression as MethodCallExpression;
Console.WriteLine("方法名:" + method.Method.Name);
for (int i = 0; i < method.Arguments.Count; i++)
VisitExpression2(method.Arguments[i], ref lambdaOut);
break;
case ExpressionType.Lambda://lambda表达式
LambdaExpression lambda = expression as LambdaExpression;
lambdaOut.Add(lambda);
VisitExpression2(lambda.Body, ref lambdaOut);
break;
case ExpressionType.Equal://相等比较
case ExpressionType.AndAlso://and条件运算
BinaryExpression binary = expression as BinaryExpression;
Console.WriteLine("运算符:" + expression.NodeType.ToString());
VisitExpression2(binary.Left, ref lambdaOut);
VisitExpression2(binary.Right, ref lambdaOut);
break;
case ExpressionType.Constant://常量值
ConstantExpression constant = expression as ConstantExpression;
Console.WriteLine("常量值:" + constant.Value.ToString());
break;
case ExpressionType.MemberAccess:
MemberExpression Member = expression as MemberExpression;
Console.WriteLine("字段名称:{0},类型:{1}", Member.Member.Name, Member.Type.ToString());
break;
case ExpressionType.Quote:
UnaryExpression Unary = expression as UnaryExpression;
VisitExpression2(Unary.Operand, ref lambdaOut);
break;
default:
Console.Write("UnKnow");
break;
}
}
接下来重新完成方式 Execute :
public TResult Execute<TResult>(Expression expression)
{
List<LambdaExpression> lambda = null;
AnalysisExpression.VisitExpression2(expression, ref lambda);//解析取得表达式数中的表达式
IEnumerable<Student> enumerable = null;
for (int i = 0; i < lambda.Count; i++)
{
//把LambdaExpression转成Expression<Func<Student, bool>>类型
//通过方法Compile()转成委托方法
Func<Student, bool> func = (lambda[i] as Expression<Func<Student, bool>>).Compile();
if (enumerable == null)
enumerable = Program.StudentArrary.Where(func);//取得IEnumerable
else
enumerable = enumerable.Where(func);
}
dynamic obj = enumerable.ToList();//(注意:这个方法的整个处理过程,你可以换成解析sql执行数据库查询,或者生成url然后请求获取数据。)
return (TResult)obj;
}
执行进程:
个体对 IQueryable 延迟加载的敞亮:
- 前段部分的询问操作符只是把逻辑解释存入表达式树,并从未远程实施sql。
- foreache实施的是 IEnumerable<T> ,但是 IEnumerable<T> 同样具备延期加载的特征。每一回迭代的时候才真的的取多少。且在使用导航属性的时候会再一次查询数据库。(后一次说延迟加载不要忘记了 IEnumerable 的佳绩哦!)
小知识:
表明式树转成拉姆da表明式:
Expression<Func<Student, bool>> expression = t => t.Name == "农码一生";
Func<Student, bool> func = expression.Compile();
总结:
公布式树的分析就停止了,当中还会有比相当多细节或重大的尚未分析到。下一次有新的体会再来总括。
大红鹰葡京会,感到表达式树就是先把表明式打垮存在树结构里(一般打垮的长河是编写翻译器达成),然后能够遵照区别的数据源或接口重建成自身想要的另外款式,这也让大家实现和谐的orm成为了恐怕。
前几日主假若对发挥式树的剖释、和落到实处团结的IQueryable<T>、IQueryProvider做了二个记录和小结,个中不定有不当的定论或说法,轻点拍!
demo下载:http://pan.baidu.com/s/1nvAksgL
正文以联合至索引目录:《C#基础知识加强》
推荐介绍阅读:
http://www.cnblogs.com/jesse2013/p/expressiontree-part1.html
http://www.cnblogs.com/jesse2013/p/expressiontree-part2.html
http://www.cnblogs.com/jesse2013/p/expressiontree-Linq-to-cnblogs.html
园友@风口上的猪推荐:
http://www.cnblogs.com/Ninputer/archive/2009/09/08/expression_tree3.html
http://blog.zhaojie.me/2009/03/expression-cache-1.html
总结:
发布式树的解析就止住了,个中还或者有为数相当的多细节或根本的尚未分析到。后一次有新的感受再来总计。
倍感表达式树就是先把表达式制伏存在树结构里(一般征服的进程是编写翻译器达成),然后能够依附区别的数据源或接口重建成温馨想要的别的款式,那也让大家落到实处本人的orm成为了只怕。
明天重大是对发挥式树的剖析、和促成协和的IQueryable<T>、IQueryProvider做了二个笔录和计算,在这之中不定有荒唐的下结论或说法,轻点拍!
demo下载:http://pan.baidu.com/s/1nvAksgL
本文以联合至索引目录:《C#基础知识加强》
推荐阅读:
http://www.cnblogs.com/jesse2013/p/expressiontree-part1.html
http://www.cnblogs.com/jesse2013/p/expressiontree-part2.html
http://www.cnblogs.com/jesse2013/p/expressiontree-Linq-to-cnblogs.html
园友@风口上的猪推荐:
http://www.cnblogs.com/Ninputer/archive/2009/09/08/expression_tree3.html
http://blog.zhaojie.me/2009/03/expression-cache-1.html
发表评论