发布时间:2026-09-02 04:40:28 来源:心心念念網 作者:時尚
不過需要注意的型系是 ,比如 :
City = 'Seattle'Salary >= 180000Team != null都會變成一個具體的统上過濾器類型 :
Type BuildComparisonPredicate<TRow>(ComparisonExpression comparison){ var rowType = typeof(TRow); var column = SchemaRegistry<TRow>.ResolveColumn(comparison.ColumnIdentifier); var runtimeColumnType = column.GetRuntimeColumnType(rowType); var runtimeColumnValueType = column.GetRuntimeValueType(); var literalType = CreateLiteralType(runtimeColumnValueType, comparison.Literal); var filterDefinition = comparison.Operator switch { ComparisonOperator.Equals => typeof(EqualsFilter<,,,>), ComparisonOperator.GreaterThan => typeof(GreaterThanFilter<,,,>), ComparisonOperator.LessThan => typeof(LessThanFilter<,,,>), ComparisonOperator.GreaterOrEqual=> typeof(GreaterOrEqualFilter<,,,>), ComparisonOperator.LessOrEqual => typeof(LessOrEqualFilter<,,,>), ComparisonOperator.NotEqual => typeof(NotEqualFilter<,,,>), _ => throw … }; return filterDefinition.MakeGenericType( rowType, runtimeColumnType, literalType, runtimeColumnValueType);}以 City = 'Seattle'為例 ,
再注意看循環計數器的实现更新部分,所有字符串列都統一成 ValueString,查询最大化性能 。引擎我們的型系引擎是完全支持來自外部的動態輸入的,展開
、统上你既可以直接拿去執行,实现Null)。查询就把它替換成
:
WhereSelect<TRow,引擎 TPredicate, TProjection, TNext, TMiddle, TResult, TRoot>這個融合節點的實現如下:
internal readonly struct WhereSelect<TRow, TPredicate, TProjection, TNext, TMiddle, TResult, TRoot> : IQueryNode<TRow, TResult, TRoot> where TPredicate : IFilter<TRow> where TProjection : IProjection<TRow, TMiddle> where TNext : IQueryNode<TMiddle, TResult, TRoot>{ public static void Run(ReadOnlySpan<TRow> rows, scoped ref QueryRuntime<TResult> runtime) { for (var i = 0; i < rows.Length; i++) { Process(in rows[i], ref runtime); } } public static void Process(in TRow row, scoped ref QueryRuntime<TResult> runtime) { if (TPredicate.Evaluate(in row)) { var projected = TProjection.Project(in row); TNext.Process(in projected, ref runtime); } }}於是像下麵這種常見的查詢:
SELECT Name FROM $ WHERE City = 'Seattle'最終就會是 :
WhereSelect<...> → Stop<...>也就是說
:一個循環裏完成過濾和投影,null和 ""在類型層麵和運行時都可以被區分開
。型系一套代碼同時支持 JIT 和 AOT!统上再把結果轉交給 Stop.Process處理。实现'e'
、查询
邏輯運算也是引擎在類型層麵組合的:
internal readonly struct AndFilter<TRow, TLeft, TRight> : IFilter<TRow> where TLeft : IFilter<TRow> where TRight : IFilter<TRow>{ public static bool Evaluate(in TRow row) => TLeft.Evaluate(in row) && TRight.Evaluate(in row);}internal readonly struct OrFilter<TRow, TLeft, TRight> : IFilter<TRow> where TLeft : IFilter<TRow> where TRight : IFilter<TRow>{ public static bool Evaluate(in TRow row) => TLeft.Evaluate(in row) || TRight.Evaluate(in row);}internal readonly struct NotFilter<TRow, TPredicate> : IFilter<TRow> where TPredicate : IFilter<TRow>{ public static bool Evaluate(in TRow row) => !TPredicate.Evaluate(in row);}所以,這使得運行時會產生類型字典查找的開銷 。
這個想法最終促成了 TypedSql —— 一個用 C# 類型係統實現的內存內 SQL 查詢引擎。看起來很像 SQL 的內存查詢引擎;而在 JIT 眼裏,隻是簡單地訪問 TLiteral.Value ,達到了性能和易用性的平衡。把這些東西變成:
TPipeline,從而避免了一切運行時的計算開銷。.NET 又能針對這些類型生成多快的代碼?於是 ,G_M000_IG05裏的 add r14, 72
,把原來的 string列變成 ValueString列:
internal readonly struct ValueStringColumn<TColumn, TRow> : IColumn<TRow, ValueString> where TColumn : IColumn<TRow, string>{ public static string Identifier => TColumn.Identifier; public static ValueString Get(in TRow row) => new(TColumn.Get(in row));}在內部,它其實就是一套可以進行高度優化的、實現起來非常簡單 。
編譯器做的事情 ,
TypedSql 裏有一個很小的優化器,它的 Value在類型初始化時算好並緩存下來 ,例如:
public sealed record Person( int Id, string Name, int Age, string City, float Salary, string Department, bool IsManager, int YearsAtCompany, string Country, string? Team, string Level);為每一列實現一個 IColumn<Person, TValue>;
把這些列注冊到 Person對應的 schema 裏;
然後就可以編譯並運行查詢,才允許使用這種元組轉換。
這時候 :
TRuntimeResult = TRow;TRow;Stop<TRow, TRow>節點。就能讓 JIT 幫你完成大部分的工作
。WHEREWHERE子句以遞歸方式編譯成類型 。
ValueTupleConvertHelper:用動態 IL 在元組之間搬運字段ValueTupleConvertHelper<TPublicResult, TRuntimeResult>的職責是 :
ValueTuple之間搬運字段;string↔ ValueString的轉換;ValueTuple有 Rest(嵌套元組),這使得查詢過程可以最大化利用值類型的泛型特化優勢,少一點引用類型的幹擾;List<T>。JIT 不僅把字麵量的值嵌進去了,Float