原来Queryable是这样实现的..
一直没去细想为什么Enumerable和Queryable提供了两套签名一致的方法.今天在扩展IQToolkit,使之支持Insert/Update/Delete的过程中,遇到了问题,用Reflector看了一下Queryable类的源码,顿时醍醐灌顶.
在给代表数据库表格的类EntityTable(实现了IQueryable<TEntity>接口)添加一个扩展方法Delete(Expression<Predicate<TEntity>>)来做生成Delete语句的标识时,发现这个方法被直接调用了,觉得很郁闷.明明微软自己的Where, Select等方法都没被调用,而是作为Expression给传到了QueryProvider里, 凭什么我自己写的方法你就不给翻译一下传过去,而是当场执行呢?
不对啊,First, Single之类的方法也是当场执行的啊,难道编译器会根据方法的返回类型(是不是相同的IQueryable<T>)来决定如何对待它们?或者,可能有某个应用于方法上的Attribute,可以控制编译器这方面的行为?
还是看看Queryable里的代码是怎么写的吧.打开Reflector一看Queryable.First方法,马上明白了:
public static TSource First<TSource>(this IQueryable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return source.Provider.Execute<TSource>(Expression.Call(null, ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource) }), new Expression[] { source.Expression }));
}
晕了,原来根本不是编译器在捣鬼!这方法纯粹是一混蛋,屁事不干的主.不单屁事不干,还指使别人说,你再来调用我吧..
再看Queryable.Where:
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
}
return source.Provider.CreateQuery<TSource>(Expression.Call(null, ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource) }), new Expression[] { source.Expression, Expression.Quote(predicate) }));
}
First和Where的区别在于两者调用了不同的方法,一个要求直接执行对应的动作,一个要求返回一个新的IQueryable<T>对象以推迟实际行为的发生.
哎,这世界上怎么那么多比我聪明的人呢?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
2007-01-22 分享一些我在开发过程中用过的资源