From abd4ace8b60ade33124da92f9ef598da17cc643d Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Thu, 20 Aug 2026 16:27:34 +0100 Subject: [PATCH 1/2] Type handlers: design note - runtime dispatch via LookupDbType, then announced attributes --- notes/typehandlers-design.md | 76 ++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 notes/typehandlers-design.md diff --git a/notes/typehandlers-design.md b/notes/typehandlers-design.md new file mode 100644 index 0000000..a81c881 --- /dev/null +++ b/notes/typehandlers-design.md @@ -0,0 +1,76 @@ +# Type handlers: the unification story + +## What the failing tests actually are + +"TypeHandlerTests ×16/provider" decomposes into four families; only the first two are +type-handler work: + +1. **Runtime `AddTypeHandler` registrations** (Issue136, Issue1959 ×2, Issue461, + Issue253 ×2, SO24740733 ×2, EnumTypeHandler-preference): the suite registers handlers + at runtime; write-side members bind raw ("No mapping exists from object type + LocalDate…" from the provider) and read-side members never consult the handler. + Issue253 is the sharp one: a *handled collection type* — vanilla checks handlers + **before** list expansion, and our #197 expansion now wins incorrectly. +2. **`AddTypeMap`** (AnsiString ×2): runtime remap of a *recognized* scalar's DbType. +3. **`SetTypeMap`/`CustomPropertyTypeMap`** (TestCustomTypeMap, Test_RemoveTypeMap): + runtime *column-name mapping* — genuinely incompatible with compile-time row + factories; the parity table's 🚫-proposal stands (decision needed). +4. **Coercion tail wearing the wrong filename** (TestBigIntForEverythingWorks: enum + from float/double column needs the pre-convert vanilla does; Issue149 strictness): + not handler work at all. + +## Tier 1: runtime dispatch, delegating to vanilla's own decision procedure + +`SqlMapper.LookupDbType(Type, name, demand, out ITypeHandler)` is public and +`[Obsolete(…, false)]` — the same suppressible tier as `PackListParameters`, and it *is* +the whole vanilla decision: handlers, the `AddTypeMap` remap, LinqBinary, +`Settings.PreferTypeHandlersForEnums`, and `EnumerableMultiParameter` (i.e. the +handler-before-expansion ordering), evaluated at execution time. `ITypeHandler` itself +(`SetValue(IDbDataParameter, object)` / `Parse(Type, object)`) is public and +non-obsolete. (`TypeHandlerCache` is obsolete-as-**error** — unusable from generated +C#, which is why vanilla can only call it from IL; no new Dapper API is needed, so no +DAP052 gate.) + +- **Write, unknown member type** (today: raw `p.Value = …`, provider throws): emit + `LookupDbType(typeof(X), name, demand: true, out var handler)`; handler present → + `handler.SetValue(p, value)` with the **raw** value (null stays null — Issue1959 pins + that the handler sees null; vanilla only sanitizes on the non-handler path); else + apply the returned DbType if any and bind as today. `demand: true` also restores + vanilla's *"The member X of type Y cannot be used as a parameter value"* — which is + exactly what MiscTests.TestUnexpectedDataMessage pins, so that clears too. +- **Write, expandable member**: same lookup *first*; handler present → single handled + parameter, else `PackListParameters` (vanilla's ordering; fixes Issue253). +- **Write, enum member**: branch on `Settings.PreferTypeHandlersForEnums` (static bool, + default false — cheap short-circuit) before the baked enum path. +- **Read, unknown member/result type**: `LookupDbType(typeof(X), "", demand: false, + out var handler)`; handler present → `(X)handler.Parse(typeof(X), reader.GetValue(i))`, + else the current `As` fallback. Per-row lookup for tier 1 — registrations are + mutable (the suite re-registers), so per-shape caching is a later optimization with a + staleness story, not a first cut. Covers constructor binding (Issue461) and the + single-column scalar form (SO24740733). + +Deliberately *not* in tier 1: + +- **`AddTypeMap` on recognized scalars** (the AnsiString pair): honoring it means every + string member pays a runtime lookup where today the DbType is baked. Possible, small, + but a per-parameter cost on the most common parameter type — decision to take + explicitly rather than slip in. +- **`SetTypeMap` family**: propose 🚫 (runtime column-mapping vs compile-time row + factories); the attribute equivalents (`[Column]` + `[UseColumnAttribute]`) are the + AOT spelling. + +## Tier 2: the announced-attribute layer (compile-time) + +`[TypeHandler]` and `TypeHandler` already ship in Dapper.AOT — the +generator just never consults them (dormant API). Wiring them gives static dispatch +(no lookup, no mutable registry, trim-friendly) and is the AOT-strict spelling to point +people at. Prior art: external PRs #117 (samcragg — the attribute shape, plus a +`Read(DbDataReader, int)` addition to `TypeHandler`) and #162 (7amou3 — static +per-file handler instances instead of per-call `new`). Both are the right *shape*; +neither implementation can land as-is post-phase-2: #162's `TypeHandlerInstanceRegistry` +keys a dictionary on `INamedTypeSymbol` inside generator state, which is exactly the +Roslyn-objects-in-cached-state trap the plain-data model exists to prevent (ModelShapeTests +enforces it). Tier 2 = their design, re-done as plain-data plans, with credit. + +Tier 1 first: it is what the test suite actually measures, needs no consumer changes, +and works with every shipped Dapper. From 166a3f2d1ba98a5d5028f81b8b5a4e0d55766b22 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Thu, 20 Aug 2026 16:57:32 +0100 Subject: [PATCH 2/2] Type handlers: runtime registrations honored end-to-end SqlMapper.AddTypeHandler registrations now work under interception, in both directions, by delegating to vanilla's own decision procedure at execution time rather than trying to see runtime state at compile time: - writes: a member type the generator does not recognize emits a dispatch through SqlMapper.LookupDbType (public, CS0618-suppressible - the same tier as PackListParameters): handler present -> handler.SetValue (with DBNull for null, never null itself - the TypeHandler interface impl NREs on a raw null); otherwise any returned DbType is applied and the value binds raw as before (demand:false deliberately - modern providers natively handle types vanilla's map does not, DateOnly being the live case until the Dapper re-enable ships). Update-mode mirrors it, so command reuse stays legal (the parameter shape is stable); an expandable member checks the handler *first*, which is the order vanilla applies (a handled collection type must not list-expand - Issue253). - reads: the lib cannot reference Dapper (a consumer may use Dapper or Dapper.StrongName, and a hard reference would split the handler registry between the two), so generated code installs a TypeHandlerBridge from a module initializer, compiled against the consumer's own Dapper; the flexible read path consults it, and a whole-type handler overrides a generated row factory (RowFactory.Resolve), matching vanilla's handler-before-member-binding order. A ModuleInitializerAttribute polyfill is emitted for down-level targets, probe-gated like the interceptor attribute; the whole feature is inert against a Dapper too old to have HasTypeHandler/LookupDbType. - char/char? stay excluded (their StringFixedLength map entry pads the round-trip); object/dynamic stay excluded (runtime-typed values); ParamMember gains TypeOfName, mirroring RowMember's, because typeof on an annotated reference type or dynamic does not compile. This also clears the bare-DataTable TVP shape and the Xml types for free - vanilla registers DataTableHandler and the XML handlers by default, and the dispatch reaches them like any other registration. Dapper test suite: 677 -> 705/793. Design and probed facts in notes/typehandlers-design.md; prior art PRs #117 and #162 (the announced- attribute tier) remain as the static-dispatch optimization, redone on the plain-data model. --- notes/parity.md | 4 +- notes/typehandlers-design.md | 22 ++ .../DapperInterceptorGenerator.cs | 118 +++++++++- .../Model/InterceptorEnvironment.cs | 9 +- .../CodeAnalysis/Model/ParamPlan.cs | 13 +- .../Writers/PreGeneratedCodeWriter.cs | 10 + .../ModuleInitializerAttribute.cs | 6 + .../InGeneration/TypeHandlerBridge.cs | 19 ++ .../IncludedGeneration.cs | 2 + src/Dapper.AOT/CommandT.Query.cs | 12 +- src/Dapper.AOT/RowFactory.cs | 20 +- src/Dapper.AOT/TypeHandlerBridge.cs | 40 ++++ .../Interceptors/BaseCommandFactory.output.cs | 21 +- .../BaseCommandFactory.output.netfx.cs | 28 ++- .../Interceptors/BatchSize.output.cs | 21 +- .../Interceptors/BatchSize.output.netfx.cs | 28 ++- .../Interceptors/Blame.output.cs | 21 +- .../Interceptors/Blame.output.netfx.cs | 28 ++- .../Interceptors/CacheCommand.output.cs | 21 +- .../Interceptors/CacheCommand.output.netfx.cs | 28 ++- .../Interceptors/Cancellation.output.cs | 21 +- .../Interceptors/Cancellation.output.netfx.cs | 28 ++- .../Interceptors/ColumnAttribute.output.cs | 21 +- .../ColumnAttribute.output.netfx.cs | 28 ++- .../Interceptors/CommandProperties.output.cs | 21 +- .../CommandProperties.output.netfx.cs | 28 ++- .../Interceptors/CustomParameters.output.cs | 21 +- .../CustomParameters.output.netfx.cs | 28 ++- .../Interceptors/DateOnly.net6.output.cs | 73 +++++- .../Interceptors/DbString.output.cs | 21 +- .../Interceptors/DbString.output.netfx.cs | 28 ++- .../Interceptors/DbValueUsage.output.cs | 21 +- .../Interceptors/DbValueUsage.output.netfx.cs | 28 ++- .../Interceptors/DynamicMember.output.cs | 21 +- .../DynamicMember.output.netfx.cs | 28 ++- .../EnumerableExtensions.output.cs | 21 +- .../EnumerableExtensions.output.netfx.cs | 28 ++- .../Interceptors/Execute.output.cs | 21 +- .../Interceptors/Execute.output.netfx.cs | 28 ++- .../Interceptors/ExecuteBatch.output.cs | 21 +- .../Interceptors/ExecuteBatch.output.netfx.cs | 28 ++- .../Interceptors/ExecuteScalar.output.cs | 21 +- .../ExecuteScalar.output.netfx.cs | 28 ++- .../Interceptors/GetRowParser.output.cs | 21 +- .../Interceptors/GetRowParser.output.netfx.cs | 28 ++- .../Interceptors/GlobalFetchSize.output.cs | 21 +- .../GlobalFetchSize.output.netfx.cs | 28 ++- .../Interceptors/IncludeSqlSource.output.cs | 21 +- .../IncludeSqlSource.output.netfx.cs | 28 ++- .../Interceptors/InheritedMembers.output.cs | 21 +- .../InheritedMembers.output.netfx.cs | 28 ++- .../Interceptors/ListExpansion.output.cs | 69 +++++- .../ListExpansion.output.netfx.cs | 76 ++++++- .../Interceptors/LiteralTokens.output.cs | 21 +- .../LiteralTokens.output.netfx.cs | 28 ++- .../Interceptors/MappedSqlDetection.output.cs | 21 +- .../MappedSqlDetection.output.netfx.cs | 28 ++- .../Interceptors/MiscDiagnostics.output.cs | 21 +- .../MiscDiagnostics.output.netfx.cs | 28 ++- .../Interceptors/NonConstant.output.cs | 21 +- .../Interceptors/NonConstant.output.netfx.cs | 28 ++- .../Interceptors/NonFactoryMethod.output.cs | 21 +- .../NonFactoryMethod.output.netfx.cs | 28 ++- .../Interceptors/OmitAttribute.output.cs | 21 +- .../OmitAttribute.output.netfx.cs | 28 ++- .../Interceptors/Query.output.cs | 21 +- .../Interceptors/Query.output.netfx.cs | 28 ++- ...ustomConstructionWithConstructor.output.cs | 21 +- ...onstructionWithConstructor.output.netfx.cs | 28 ++- ...tomConstructionWithFactoryMethod.output.cs | 21 +- ...structionWithFactoryMethod.output.netfx.cs | 28 ++- .../Interceptors/QueryDetection.output.cs | 21 +- .../QueryDetection.output.netfx.cs | 28 ++- .../QueryEnumerableParams.output.cs | 21 +- .../QueryEnumerableParams.output.netfx.cs | 28 ++- .../Interceptors/QueryNonGeneric.output.cs | 21 +- .../QueryNonGeneric.output.netfx.cs | 28 ++- .../Interceptors/QueryPrimitive.output.cs | 21 +- .../QueryPrimitive.output.netfx.cs | 28 ++- .../Interceptors/QueryStrictBind.output.cs | 21 +- .../QueryStrictBind.output.netfx.cs | 28 ++- .../Interceptors/QueryUntyped.output.cs | 21 +- .../Interceptors/QueryUntyped.output.netfx.cs | 28 ++- .../Interceptors/RequiredProperties.output.cs | 21 +- .../RequiredProperties.output.netfx.cs | 28 ++- .../Interceptors/RowCountHint.output.cs | 21 +- .../Interceptors/RowCountHint.output.netfx.cs | 28 ++- .../Interceptors/Single.output.cs | 21 +- .../Interceptors/Single.output.netfx.cs | 28 ++- .../Interceptors/SqlDetection.output.cs | 21 +- .../Interceptors/SqlDetection.output.netfx.cs | 28 ++- .../Interceptors/SqlParse.output.cs | 21 +- .../Interceptors/SqlParse.output.netfx.cs | 28 ++- .../Interceptors/Techempower.output.cs | 21 +- .../Interceptors/Techempower.output.netfx.cs | 28 ++- .../Interceptors/TopLevelStatements.output.cs | 21 +- .../TopLevelStatements.output.netfx.cs | 28 ++- .../Interceptors/TsqlTips.output.cs | 37 ++- .../Interceptors/TsqlTips.output.netfx.cs | 44 +++- .../Interceptors/TypeHandlerDispatch.input.cs | 31 +++ .../TypeHandlerDispatch.output.cs | 203 +++++++++++++++++ .../TypeHandlerDispatch.output.netfx.cs | 210 ++++++++++++++++++ .../TypeHandlerDispatch.output.netfx.txt | 4 + .../TypeHandlerDispatch.output.txt | 4 + .../UnconstructableResults.output.cs | 21 +- .../UnconstructableResults.output.netfx.cs | 28 ++- 106 files changed, 2968 insertions(+), 116 deletions(-) create mode 100644 src/Dapper.AOT.Analyzers/InGeneration/ModuleInitializerAttribute.cs create mode 100644 src/Dapper.AOT.Analyzers/InGeneration/TypeHandlerBridge.cs create mode 100644 src/Dapper.AOT/TypeHandlerBridge.cs create mode 100644 test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.input.cs create mode 100644 test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.cs create mode 100644 test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.netfx.cs create mode 100644 test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.netfx.txt create mode 100644 test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.txt diff --git a/notes/parity.md b/notes/parity.md index 144f70c..266f015 100644 --- a/notes/parity.md +++ b/notes/parity.md @@ -90,8 +90,8 @@ Two levers change several complexity scores and are worth naming up front: | enum results (string→enum case-insens., widening, `ShortEnum`) | ⚠️❓ | high | low-med | Dapper recently changed precedence (prefer type handlers, #2200) — match the *new* behavior | | `MatchNamesWithUnderscores` | ❓ | med-high | low | snake_case databases; needs a compile-time equivalent (global option/attr) | | `SetTypeMap` / `CustomPropertyTypeMap` / `ITypeMap` / `TypeMapProvider` | ❌ 🚫? | med | med | runtime config by definition; AOT spelling is `[Column]`+`[UseColumnAttribute]`. Proposal: declare 🚫 for the runtime API, ship attribute equivalents + migration guidance | -| `AddTypeHandler` / `TypeHandler` / `StringTypeHandler` | ❌→⚠️ | **high** | med-high | AOT has its own `TypeHandler`; needs the unification story (how does a *Dapper* handler registration become an AOT one?) | -| `AddTypeMap` / `RemoveTypeMap` (scalar DbType map) | ❌ ❓ | low-med | low | e.g. `DateTime`→`DateTime2`; global compile-time option | +| `AddTypeHandler` / `TypeHandler` / `StringTypeHandler` | ✅ | — | — | runtime registrations honored end-to-end: writes dispatch through vanilla's `LookupDbType` (unrecognized member types), reads through a generated-code bridge into the AOT readers (the lib cannot reference Dapper: StrongName would split the registry). Whole-type handlers override generated row factories, matching vanilla. See [typehandlers-design.md](typehandlers-design.md); the announced-attribute tier (static dispatch, prior art #117/#162) remains as an optimization | +| `AddTypeMap` / `RemoveTypeMap` (scalar DbType map) | ⚠️ | low-med | low | honored for member types the generator does not recognize (they route through `LookupDbType` at execution); *recognized* scalars (the string→AnsiString tests) keep their baked DbType — honoring those means a per-parameter lookup on the hottest types, a trade to take explicitly | | `Settings.ApplyNullValues` | ❓ | low | low | | | coercion matrix (`char`, `Nullable`, `Convert.ChangeType` fidelity) | ❓ | high | med | silent-wrongness risk; test-driven, differential against Dapper | | column-level error reporting (`ThrowDataException` names column+value) | ❓ | med | low | DX parity worth keeping | diff --git a/notes/typehandlers-design.md b/notes/typehandlers-design.md index a81c881..933a9e6 100644 --- a/notes/typehandlers-design.md +++ b/notes/typehandlers-design.md @@ -74,3 +74,25 @@ enforces it). Tier 2 = their design, re-done as plain-data plans, with credit. Tier 1 first: it is what the test suite actually measures, needs no consumer changes, and works with every shipped Dapper. + +## Outcomes (recorded after implementation) + +- **695 -> 705/793**: the whole runtime-handler family cleared (Issue136, Issue1959 x4, + Issue253 x2, Issue461, SO24740733 x2, Issue149, the enum-preference test), plus the bare + `DataTable` TVP pair and the Xml tests - vanilla registers `DataTableHandler` and the XML + handlers *by default*, so the dispatch reaches them for free. +- **`demand: false`, not vanilla's `demand: true`**, deliberately: when nothing matches we + keep the previous raw bind, because modern providers natively handle types vanilla's map + does not (DateOnly until the Dapper re-enable ships being the live case). Message parity + for genuinely-unusable types (TestUnexpectedDataMessage) is deferred to that bump. +- **A handler receives DBNull, never null** - `SqlMapper.TypeHandler`'s explicit + interface impl special-cases DBNull and NREs on a raw null (struct cast); vanilla's IL + coalesces first, so we do too. +- **`char`/`char?` stay excluded from dispatch**: their map entry is StringFixedLength + *with* SetType, and applying it pads the round-trip (TestCharInputAndOutput). Vanilla + converts char members to length-1 strings on the way out - coercion-tail work, not + handler work. +- **The build-exit lesson, again**: the first measurement showed zero movement because the + harness build had silently failed (generated `typeof` on an annotated reference type is + CS8639, on `dynamic` CS1962 - hence `ParamMember.TypeOfName`, mirroring `RowMember`'s) + and `--no-build` ran stale binaries. Check the exit code, not the presence of output. diff --git a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs index 1139de5..403235f 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs @@ -280,6 +280,10 @@ internal static InterceptorEnvironment CreateEnvironment(Compilation compilation allowUnsafe: compilation.Options is CSharpCompilationOptions cSharp && cSharp.AllowUnsafe, assemblyName: compilation.AssemblyName, hasInterceptsLocationAttribute: PreGeneratedCodeWriter.HasInterceptsLocationAttribute(compilation), + hasModuleInitializer: compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.ModuleInitializerAttribute") is not null, + hasVanillaTypeHandlers: compilation.GetTypeByMetadataName("Dapper.SqlMapper") is { } sqlMapper + && !sqlMapper.GetMembers("HasTypeHandler").IsEmpty + && !sqlMapper.GetMembers("LookupDbType").IsEmpty, needsCommandPrep: needsCommandPrep, baseCommandFactoryName: baseFactory, baseFactoryCanConstruct: canConstruct, @@ -589,6 +593,18 @@ internal void Generate(in GenerateState ctx) sb.Outdent().Outdent(); // ends our generated file-scoped class and the namespace + if (env.HasVanillaTypeHandlers) + { + // runtime SqlMapper.AddTypeHandler registrations reach the AOT readers through a + // bridge installed from generated code, which compiles against the consumer's own + // Dapper (the lib cannot reference it: Dapper vs Dapper.StrongName would split) + ctx.GeneratorContext.IncludeGenerationType(IncludedGeneration.TypeHandlerBridge); + if (!env.HasModuleInitializer) + { + ctx.GeneratorContext.IncludeGenerationType(IncludedGeneration.ModuleInitializerAttribute); + } + } + var preGeneratedCodeWriter = new PreGeneratedCodeWriter(sb, env.HasInterceptsLocationAttribute); preGeneratedCodeWriter.Write(ctx.GeneratorContext.IncludedGenerationTypes); @@ -1329,9 +1345,77 @@ private static void WriteArgs(in GenerateState ctx, ParamPlan? parameterType, Co // string_split settings, and provider array support flags &= ~WriteArgsFlags.CanPrepare; // parameter shape varies by list size sb.Append("#pragma warning disable CS0618 // list-expansion: this *is* the library usage").NewLine() + .Append("_ = global::Dapper.SqlMapper.LookupDbType(typeof(").Append(member.TypeOfName) + .Append("), ").AppendVerbatimLiteral(member.DbName) + .Append(", false, out var typeHandler").Append(member.CodeName).Append(");").NewLine() + .Append("// a runtime type-handler for the collection type wins over expansion,").NewLine() + .Append("// which is the order vanilla's own decision procedure applies").NewLine() + .Append("if (typeHandler").Append(member.CodeName).Append(" is not null)").Indent().NewLine() + .Append("var hp = cmd.CreateParameter();").NewLine() + .Append("hp.ParameterName = ").AppendVerbatimLiteral(member.DbName).Append(";").NewLine() + .Append("hp.Direction = global::System.Data.ParameterDirection.Input;").NewLine() + .Append("typeHandler").Append(member.CodeName).Append(".SetValue(hp, (object?)") + .Append(source).Append(".").Append(member.CodeName).Append(" ?? global::System.DBNull.Value);").NewLine() + .Append("ps.Add(hp);").Outdent().NewLine() + .Append("else").Indent().NewLine() .Append("global::Dapper.SqlMapper.PackListParameters(cmd.Command!, ").AppendVerbatimLiteral(member.DbName) - .Append(", ").Append(source).Append(".").Append(member.CodeName).Append(");").NewLine() + .Append(", ").Append(source).Append(".").Append(member.CodeName).Append(");").Outdent().NewLine() + .Append("#pragma warning restore CS0618").NewLine(); + break; + } + if (!member.HasDbType && !member.IsDbString && member.TypeOfName != "object" && member.TypeOfName != "char") + { + // an unrecognized member type: defer to vanilla's own decision procedure at + // execution time - runtime type-handlers (SqlMapper.AddTypeHandler), the + // AddTypeMap remap, and PreferTypeHandlersForEnums all live in there. + // demand:false, deliberately: when nothing matches we keep today's raw bind, + // because modern providers natively handle types vanilla's map does not + // (DateOnly, until Dapper ships the re-enable) - revisit for message parity + flags &= ~WriteArgsFlags.CanPrepare; + var suffix = member.CodeName; + sb.Append("#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage").NewLine() + .Append("var dbType").Append(suffix).Append(" = global::Dapper.SqlMapper.LookupDbType(typeof(") + .Append(member.TypeOfName).Append("), ").AppendVerbatimLiteral(member.DbName) + .Append(", false, out var typeHandler").Append(suffix).Append(");").NewLine() .Append("#pragma warning restore CS0618").NewLine(); + sb.Append("p = cmd.CreateParameter();").NewLine(); + sb.Append("p.ParameterName = ").AppendVerbatimLiteral(member.DbName).Append(";").NewLine(); + AppendDbParameterSetting(sb, "Size", member.EffectiveSize); + AppendDbParameterSetting(sb, "Precision", member.Precision); + AppendDbParameterSetting(sb, "Scale", member.Scale); + sb.Append("p.Direction = global::System.Data.ParameterDirection.").Append(direction switch + { + ParameterDirection.Input => nameof(ParameterDirection.Input), + ParameterDirection.InputOutput => nameof(ParameterDirection.InputOutput), + ParameterDirection.Output => nameof(ParameterDirection.Output), + ParameterDirection.ReturnValue => nameof(ParameterDirection.ReturnValue), + _ => direction.ToString(), + }).Append(";").NewLine(); + sb.Append("if (typeHandler").Append(suffix).Append(" is not null)").Indent().NewLine() + .Append("typeHandler").Append(suffix).Append(".SetValue(p, (object?)") + .Append(source).Append(".").Append(member.CodeName).Append(" ?? global::System.DBNull.Value);").Outdent().NewLine() + .Append("else").Indent().NewLine() + .Append("if (dbType").Append(suffix).Append(" is not null) p.DbType = dbType").Append(suffix).Append(".GetValueOrDefault();").NewLine(); + switch (direction) + { + case ParameterDirection.Input: + case ParameterDirection.InputOutput: + sb.Append("p.Value = AsValue(").Append(source).Append(".").Append(member.CodeName).Append(");").NewLine(); + break; + default: + sb.Append("p.Value = global::System.DBNull.Value;").NewLine(); + break; + } + sb.Outdent().NewLine(); + sb.Append("ps.Add(p);").NewLine(); + switch (direction) + { + case ParameterDirection.InputOutput: + case ParameterDirection.Output: + case ParameterDirection.ReturnValue: + flags |= WriteArgsFlags.NeedsPostProcess; + break; + } break; } sb.Append("p = cmd.CreateParameter();").NewLine(); @@ -1419,6 +1503,38 @@ private static void WriteArgs(in GenerateState ctx, ParamPlan? parameterType, Co break; } + if (!member.HasDbType && !member.IsDbString && member.TypeOfName != "object" && member.TypeOfName != "char") + { + // mirror the Add-mode runtime dispatch; the parameter shape is stable + // (always exactly one), so command reuse stays legal + sb.Append("#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage").NewLine() + .Append("_ = global::Dapper.SqlMapper.LookupDbType(typeof(").Append(member.TypeOfName) + .Append("), ").AppendVerbatimLiteral(member.DbName) + .Append(", false, out var typeHandler").Append(member.CodeName).Append(");").NewLine() + .Append("#pragma warning restore CS0618").NewLine() + .Append("if (typeHandler").Append(member.CodeName).Append(" is not null)").Indent().NewLine() + .Append("typeHandler").Append(member.CodeName).Append(".SetValue(ps["); + if ((flags & WriteArgsFlags.NeedsTest) != 0) sb.AppendVerbatimLiteral(member.DbName); + else sb.Append(parameterIndex); + sb.Append("], (object?)").Append(source).Append(".").Append(member.CodeName).Append(" ?? global::System.DBNull.Value);").Outdent().NewLine() + .Append("else").Indent().NewLine() + .Append("ps["); + if ((flags & WriteArgsFlags.NeedsTest) != 0) sb.AppendVerbatimLiteral(member.DbName); + else sb.Append(parameterIndex); + sb.Append("].Value = "); + switch (direction) + { + case ParameterDirection.Input: + case ParameterDirection.InputOutput: + sb.Append("AsValue(").Append(source).Append(".").Append(member.CodeName).Append(");"); + break; + default: + sb.Append("global::System.DBNull.Value;"); + break; + } + sb.Outdent().NewLine(); + break; + } sb.Append("ps["); if ((flags & WriteArgsFlags.NeedsTest) != 0) sb.AppendVerbatimLiteral(member.DbName); else sb.Append(parameterIndex); diff --git a/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/InterceptorEnvironment.cs b/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/InterceptorEnvironment.cs index cf97fa0..ef72c95 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/InterceptorEnvironment.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/InterceptorEnvironment.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Dapper.CodeAnalysis.Model; @@ -11,6 +11,8 @@ internal sealed class InterceptorEnvironment : IEquatable] at module level, if any public bool BaseFactoryCanConstruct { get; } @@ -18,12 +20,15 @@ internal sealed class InterceptorEnvironment : IEquatable specialCommandTypes, ParamPlan systemObjectPlan) { AllowUnsafe = allowUnsafe; AssemblyName = assemblyName; HasInterceptsLocationAttribute = hasInterceptsLocationAttribute; + HasModuleInitializer = hasModuleInitializer; + HasVanillaTypeHandlers = hasVanillaTypeHandlers; NeedsCommandPrep = needsCommandPrep; BaseCommandFactoryName = baseCommandFactoryName; BaseFactoryCanConstruct = baseFactoryCanConstruct; @@ -35,6 +40,8 @@ public bool Equals(InterceptorEnvironment? other) => other is not null && AllowUnsafe == other.AllowUnsafe && string.Equals(AssemblyName, other.AssemblyName, StringComparison.Ordinal) && HasInterceptsLocationAttribute == other.HasInterceptsLocationAttribute + && HasModuleInitializer == other.HasModuleInitializer + && HasVanillaTypeHandlers == other.HasVanillaTypeHandlers && NeedsCommandPrep == other.NeedsCommandPrep && string.Equals(BaseCommandFactoryName, other.BaseCommandFactoryName, StringComparison.Ordinal) && BaseFactoryCanConstruct == other.BaseFactoryCanConstruct diff --git a/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/ParamPlan.cs b/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/ParamPlan.cs index 55eaf64..cd9b7ce 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/ParamPlan.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/ParamPlan.cs @@ -162,11 +162,12 @@ public override int GetHashCode() public byte? Precision { get; } public byte? Scale { get; } public string TypeName { get; } // emitted (Append) form, for Parse in post-process + public string TypeOfName { get; } // for typeof(...): dynamic becomes object, annotations stripped private ParamMember(bool isMapped, bool isCancellation, bool isRowCount, string codeName, string dbName, ParameterDirection direction, bool isDbString, bool isExpandable, bool isCustom, bool isValueType, bool hasDbType, string? dbTypeName, int? effectiveSize, - bool useSetValueWithDefaultSize, byte? precision, byte? scale, string typeName) + bool useSetValueWithDefaultSize, byte? precision, byte? scale, string typeName, string typeOfName) { IsMapped = isMapped; IsCancellation = isCancellation; @@ -185,13 +186,14 @@ private ParamMember(bool isMapped, bool isCancellation, bool isRowCount, string Precision = precision; Scale = scale; TypeName = typeName; + TypeOfName = typeOfName; } public static ParamMember Create(in ElementMember member) { if (!member.IsMapped) { - return new(false, false, false, "", "", default, false, false, false, false, false, null, null, false, null, null, ""); + return new(false, false, false, "", "", default, false, false, false, false, false, null, null, false, null, null, "", ""); } var dbType = member.GetDbType(out _); var size = member.TryGetValue("Size"); @@ -219,7 +221,9 @@ public static ParamMember Create(in ElementMember member) member.DapperSpecialType is DapperSpecialType.CustomQueryParameter, member.CodeType!.IsValueType, dbType is not null, dbType?.ToString(), size, useSetValueWithDefaultSize, member.TryGetValue("Precision"), member.TryGetValue("Scale"), - CodeWriter.GetAppendTypeName(member.CodeType!)); + CodeWriter.GetAppendTypeName(member.CodeType!), + member.CodeType!.TypeKind == TypeKind.Dynamic ? "object" + : CodeWriter.GetAppendTypeName(MakeNonNullable(member.CodeType!))); } public bool Equals(ParamMember other) => IsMapped == other.IsMapped @@ -238,7 +242,8 @@ public bool Equals(ParamMember other) => IsMapped == other.IsMapped && UseSetValueWithDefaultSize == other.UseSetValueWithDefaultSize && Precision == other.Precision && Scale == other.Scale - && string.Equals(TypeName, other.TypeName, StringComparison.Ordinal); + && string.Equals(TypeName, other.TypeName, StringComparison.Ordinal) + && string.Equals(TypeOfName, other.TypeOfName, StringComparison.Ordinal); public override bool Equals(object? obj) => obj is ParamMember other && Equals(other); public override int GetHashCode() => IsMapped ? StringComparer.Ordinal.GetHashCode(CodeName) : 0; diff --git a/src/Dapper.AOT.Analyzers/CodeAnalysis/Writers/PreGeneratedCodeWriter.cs b/src/Dapper.AOT.Analyzers/CodeAnalysis/Writers/PreGeneratedCodeWriter.cs index 8de835c..01c0f1c 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/Writers/PreGeneratedCodeWriter.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/Writers/PreGeneratedCodeWriter.cs @@ -60,6 +60,16 @@ public void Write(IncludedGeneration includedGenerations) { _codeWriter.NewLine().Append(Resources.ReadString("Dapper.InGeneration.DapperHelpers.cs")); } + + if (includedGenerations.HasAny(IncludedGeneration.ModuleInitializerAttribute)) + { + _codeWriter.NewLine().Append(Resources.ReadString("Dapper.InGeneration.ModuleInitializerAttribute.cs")); + } + + if (includedGenerations.HasAny(IncludedGeneration.TypeHandlerBridge)) + { + _codeWriter.NewLine().Append(Resources.ReadString("Dapper.InGeneration.TypeHandlerBridge.cs")); + } } void WriteInterceptsLocationAttribute() diff --git a/src/Dapper.AOT.Analyzers/InGeneration/ModuleInitializerAttribute.cs b/src/Dapper.AOT.Analyzers/InGeneration/ModuleInitializerAttribute.cs new file mode 100644 index 0000000..d8ea8f5 --- /dev/null +++ b/src/Dapper.AOT.Analyzers/InGeneration/ModuleInitializerAttribute.cs @@ -0,0 +1,6 @@ +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} diff --git a/src/Dapper.AOT.Analyzers/InGeneration/TypeHandlerBridge.cs b/src/Dapper.AOT.Analyzers/InGeneration/TypeHandlerBridge.cs new file mode 100644 index 0000000..9da7057 --- /dev/null +++ b/src/Dapper.AOT.Analyzers/InGeneration/TypeHandlerBridge.cs @@ -0,0 +1,19 @@ +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/src/Dapper.AOT.Analyzers/IncludedGeneration.cs b/src/Dapper.AOT.Analyzers/IncludedGeneration.cs index dc540e7..fb1b339 100644 --- a/src/Dapper.AOT.Analyzers/IncludedGeneration.cs +++ b/src/Dapper.AOT.Analyzers/IncludedGeneration.cs @@ -8,5 +8,7 @@ internal enum IncludedGeneration None = 0, InterceptsLocationAttribute = 1 << 0, DbStringHelpers = 1 << 1, + TypeHandlerBridge = 1 << 2, + ModuleInitializerAttribute = 1 << 3, } } diff --git a/src/Dapper.AOT/CommandT.Query.cs b/src/Dapper.AOT/CommandT.Query.cs index ea7c708..32af9fb 100644 --- a/src/Dapper.AOT/CommandT.Query.cs +++ b/src/Dapper.AOT/CommandT.Query.cs @@ -34,7 +34,7 @@ public List QueryBuffered(TArgs args, [DapperAot] RowFactory? ? CommandUtils.UnsafeSlice(stackalloc int[RowFactory.MAX_STACK_TOKENS], state.Reader.FieldCount) : state.Lease(); - var tokenState = (rowFactory ??= RowFactory.Default).Tokenize(state.Reader, readWriteTokens, 0); + var tokenState = (rowFactory = RowFactory.Resolve(rowFactory)).Tokenize(state.Reader, readWriteTokens, 0); results = RowFactory.GetRowBuffer(rowCountHint); ReadOnlySpan readOnlyTokens = readWriteTokens; // avoid multiple conversions do @@ -75,7 +75,7 @@ public async Task> QueryBufferedAsync(TArgs args, [DapperAot] R List results; if (await state.Reader.ReadAsync(cancellationToken)) { - var tokenState = (rowFactory ??= RowFactory.Default).Tokenize(state.Reader, state.Lease(), 0); + var tokenState = (rowFactory = RowFactory.Resolve(rowFactory)).Tokenize(state.Reader, state.Lease(), 0); results = RowFactory.GetRowBuffer(rowCountHint); do { @@ -114,7 +114,7 @@ public async IAsyncEnumerable QueryUnbufferedAsync(TArgs args, [Dapp if (await state.Reader.ReadAsync(cancellationToken)) { - var tokenState = (rowFactory ??= RowFactory.Default).Tokenize(state.Reader, state.Lease(), 0); + var tokenState = (rowFactory = RowFactory.Resolve(rowFactory)).Tokenize(state.Reader, state.Lease(), 0); do { yield return rowFactory.Read(state.Reader, state.Tokens, 0, tokenState); @@ -144,7 +144,7 @@ public IEnumerable QueryUnbuffered(TArgs args, [DapperAot] RowFactor if (state.Reader.Read()) { - var tokenState = (rowFactory ??= RowFactory.Default).Tokenize(state.Reader, state.Lease(), 0); + var tokenState = (rowFactory = RowFactory.Resolve(rowFactory)).Tokenize(state.Reader, state.Lease(), 0); do { yield return rowFactory.Read(state.Reader, state.Tokens, 0, tokenState); @@ -184,7 +184,7 @@ static CommandBehavior SingleFlags(OneRowFlags flags) TRow? result = default; if (state.Reader.Read()) { - result = (rowFactory ??= RowFactory.Default).Read(state.Reader, ref state.Leased); + result = (rowFactory = RowFactory.Resolve(rowFactory)).Read(state.Reader, ref state.Leased); state.Return(); if (state.Reader.Read()) @@ -228,7 +228,7 @@ static CommandBehavior SingleFlags(OneRowFlags flags) TRow? result = default; if (await state.Reader.ReadAsync(cancellationToken)) { - result = (rowFactory ??= RowFactory.Default).Read(state.Reader, ref state.Leased); + result = (rowFactory = RowFactory.Resolve(rowFactory)).Read(state.Reader, ref state.Leased); state.Return(); if (await state.Reader.ReadAsync(cancellationToken)) diff --git a/src/Dapper.AOT/RowFactory.cs b/src/Dapper.AOT/RowFactory.cs index afc2ca6..d691288 100644 --- a/src/Dapper.AOT/RowFactory.cs +++ b/src/Dapper.AOT/RowFactory.cs @@ -60,7 +60,17 @@ public static class Inbuilt /// or methods like would not be appropriate /// protected static T GetValue(DbDataReader reader, int fieldOffset) - => CommandUtils.As(reader.GetValue(fieldOffset)); + { + var value = reader.GetValue(fieldOffset); + // a runtime-registered Dapper type-handler wins over conversion, matching vanilla; + // this is the flexible (type-mismatch) path, so the lookup is off the hot exact path + if (value is not null and not DBNull + && TypeHandlerBridge.TryParse(typeof(T), value, out var parsed)) + { + return (T)parsed!; + } + return CommandUtils.As(value); + } /// /// Gets a value directly, using the most appropriate helper method when available ( etc), @@ -155,6 +165,14 @@ public class RowFactory : RowFactory { private static RowFactory? _default; internal static RowFactory Default => _default ??= new(); + + /// + /// A whole-type runtime Dapper type-handler wins over a generated (member-binding) + /// factory, matching vanilla, where the handler is consulted before any member binding; + /// the default factory's flexible read path performs the actual handler dispatch + /// + internal static RowFactory Resolve(RowFactory? factory) + => factory is null || TypeHandlerBridge.Has(typeof(T)) ? Default : factory; /// /// Create a new instance /// diff --git a/src/Dapper.AOT/TypeHandlerBridge.cs b/src/Dapper.AOT/TypeHandlerBridge.cs new file mode 100644 index 0000000..4de01a1 --- /dev/null +++ b/src/Dapper.AOT/TypeHandlerBridge.cs @@ -0,0 +1,40 @@ +using System; +using System.ComponentModel; + +namespace Dapper; + +/// +/// Bridges runtime Dapper type-handler registrations (SqlMapper.AddTypeHandler) into +/// Dapper.AOT's readers. This library deliberately does not reference Dapper (a consumer +/// may be using Dapper or Dapper.StrongName, and a hard reference would load - and split +/// the handler registry between - both); instead, generated code, which compiles against +/// the consumer's own Dapper, installs these callbacks from a module initializer. +/// +[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] +public static class TypeHandlerBridge +{ + private static Func? s_hasHandler; + private static Func? s_parse; + + /// + /// Installs the lookup callbacks; intended to be called from generated code only + /// + public static void Configure(Func hasHandler, Func parse) + { + s_hasHandler = hasHandler ?? throw new ArgumentNullException(nameof(hasHandler)); + s_parse = parse ?? throw new ArgumentNullException(nameof(parse)); + } + + internal static bool Has(Type type) => s_hasHandler?.Invoke(type) ?? false; + + internal static bool TryParse(Type type, object value, out object? parsed) + { + if (s_hasHandler?.Invoke(type) == true) + { + parsed = s_parse!(type, value); + return true; + } + parsed = null; + return false; + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/BaseCommandFactory.output.cs b/test/Dapper.AOT.Test/Interceptors/BaseCommandFactory.output.cs index 7936f22..4e0e4fa 100644 --- a/test/Dapper.AOT.Test/Interceptors/BaseCommandFactory.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/BaseCommandFactory.output.cs @@ -92,4 +92,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/BaseCommandFactory.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/BaseCommandFactory.output.netfx.cs index 7936f22..ed51940 100644 --- a/test/Dapper.AOT.Test/Interceptors/BaseCommandFactory.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/BaseCommandFactory.output.netfx.cs @@ -92,4 +92,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/BatchSize.output.cs b/test/Dapper.AOT.Test/Interceptors/BatchSize.output.cs index 42ed418..3ded2eb 100644 --- a/test/Dapper.AOT.Test/Interceptors/BatchSize.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/BatchSize.output.cs @@ -141,4 +141,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/BatchSize.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/BatchSize.output.netfx.cs index 42ed418..768b3a9 100644 --- a/test/Dapper.AOT.Test/Interceptors/BatchSize.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/BatchSize.output.netfx.cs @@ -141,4 +141,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Blame.output.cs b/test/Dapper.AOT.Test/Interceptors/Blame.output.cs index c8ca323..a74dada 100644 --- a/test/Dapper.AOT.Test/Interceptors/Blame.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/Blame.output.cs @@ -78,4 +78,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Blame.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/Blame.output.netfx.cs index c8ca323..a708731 100644 --- a/test/Dapper.AOT.Test/Interceptors/Blame.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/Blame.output.netfx.cs @@ -78,4 +78,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/CacheCommand.output.cs b/test/Dapper.AOT.Test/Interceptors/CacheCommand.output.cs index 0786934..6d30df7 100644 --- a/test/Dapper.AOT.Test/Interceptors/CacheCommand.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/CacheCommand.output.cs @@ -251,4 +251,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/CacheCommand.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/CacheCommand.output.netfx.cs index 0786934..dbe5002 100644 --- a/test/Dapper.AOT.Test/Interceptors/CacheCommand.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/CacheCommand.output.netfx.cs @@ -251,4 +251,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Cancellation.output.cs b/test/Dapper.AOT.Test/Interceptors/Cancellation.output.cs index 5e7b41f..81b17d2 100644 --- a/test/Dapper.AOT.Test/Interceptors/Cancellation.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/Cancellation.output.cs @@ -160,4 +160,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Cancellation.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/Cancellation.output.netfx.cs index 5e7b41f..08e7d80 100644 --- a/test/Dapper.AOT.Test/Interceptors/Cancellation.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/Cancellation.output.netfx.cs @@ -160,4 +160,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/ColumnAttribute.output.cs b/test/Dapper.AOT.Test/Interceptors/ColumnAttribute.output.cs index 95e4a99..04c08ef 100644 --- a/test/Dapper.AOT.Test/Interceptors/ColumnAttribute.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/ColumnAttribute.output.cs @@ -141,4 +141,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/ColumnAttribute.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/ColumnAttribute.output.netfx.cs index 95e4a99..29ecefa 100644 --- a/test/Dapper.AOT.Test/Interceptors/ColumnAttribute.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/ColumnAttribute.output.netfx.cs @@ -141,4 +141,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/CommandProperties.output.cs b/test/Dapper.AOT.Test/Interceptors/CommandProperties.output.cs index 04baf13..bf852c6 100644 --- a/test/Dapper.AOT.Test/Interceptors/CommandProperties.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/CommandProperties.output.cs @@ -395,4 +395,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/CommandProperties.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/CommandProperties.output.netfx.cs index 04baf13..69055ff 100644 --- a/test/Dapper.AOT.Test/Interceptors/CommandProperties.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/CommandProperties.output.netfx.cs @@ -395,4 +395,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/CustomParameters.output.cs b/test/Dapper.AOT.Test/Interceptors/CustomParameters.output.cs index dd03233..b9761d1 100644 --- a/test/Dapper.AOT.Test/Interceptors/CustomParameters.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/CustomParameters.output.cs @@ -159,4 +159,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/CustomParameters.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/CustomParameters.output.netfx.cs index dd03233..55d58ff 100644 --- a/test/Dapper.AOT.Test/Interceptors/CustomParameters.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/CustomParameters.output.netfx.cs @@ -159,4 +159,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/DateOnly.net6.output.cs b/test/Dapper.AOT.Test/Interceptors/DateOnly.net6.output.cs index 65050cd..6569066 100644 --- a/test/Dapper.AOT.Test/Interceptors/DateOnly.net6.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/DateOnly.net6.output.cs @@ -130,10 +130,22 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var typed = Cast(args, static () => new { BirthDate = default(global::System.DateOnly) }); // expected shape var ps = cmd.Parameters; global::System.Data.Common.DbParameter p; + #pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + var dbTypeBirthDate = global::Dapper.SqlMapper.LookupDbType(typeof(global::System.DateOnly), "BirthDate", false, out var typeHandlerBirthDate); + #pragma warning restore CS0618 p = cmd.CreateParameter(); p.ParameterName = "BirthDate"; p.Direction = global::System.Data.ParameterDirection.Input; - p.Value = AsValue(typed.BirthDate); + if (typeHandlerBirthDate is not null) + { + typeHandlerBirthDate.SetValue(p, (object?)typed.BirthDate ?? global::System.DBNull.Value); + } + else + { + if (dbTypeBirthDate is not null) p.DbType = dbTypeBirthDate.GetValueOrDefault(); + p.Value = AsValue(typed.BirthDate); + + } ps.Add(p); } @@ -141,7 +153,17 @@ public override void UpdateParameters(in global::Dapper.UnifiedCommand cmd, obje { var typed = Cast(args, static () => new { BirthDate = default(global::System.DateOnly) }); // expected shape var ps = cmd.Parameters; - ps[0].Value = AsValue(typed.BirthDate); + #pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(typeof(global::System.DateOnly), "BirthDate", false, out var typeHandlerBirthDate); + #pragma warning restore CS0618 + if (typeHandlerBirthDate is not null) + { + typeHandlerBirthDate.SetValue(ps[0], (object?)typed.BirthDate ?? global::System.DBNull.Value); + } + else + { + ps[0].Value = AsValue(typed.BirthDate); + } } @@ -154,17 +176,39 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, global: { var ps = cmd.Parameters; global::System.Data.Common.DbParameter p; + #pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + var dbTypeBirthDate = global::Dapper.SqlMapper.LookupDbType(typeof(global::System.DateOnly), "BirthDate", false, out var typeHandlerBirthDate); + #pragma warning restore CS0618 p = cmd.CreateParameter(); p.ParameterName = "BirthDate"; p.Direction = global::System.Data.ParameterDirection.Input; - p.Value = AsValue(args.BirthDate); + if (typeHandlerBirthDate is not null) + { + typeHandlerBirthDate.SetValue(p, (object?)args.BirthDate ?? global::System.DBNull.Value); + } + else + { + if (dbTypeBirthDate is not null) p.DbType = dbTypeBirthDate.GetValueOrDefault(); + p.Value = AsValue(args.BirthDate); + + } ps.Add(p); } public override void UpdateParameters(in global::Dapper.UnifiedCommand cmd, global::Foo.QueryModel args) { var ps = cmd.Parameters; - ps[0].Value = AsValue(args.BirthDate); + #pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(typeof(global::System.DateOnly), "BirthDate", false, out var typeHandlerBirthDate); + #pragma warning restore CS0618 + if (typeHandlerBirthDate is not null) + { + typeHandlerBirthDate.SetValue(ps[0], (object?)args.BirthDate ?? global::System.DBNull.Value); + } + else + { + ps[0].Value = AsValue(args.BirthDate); + } } @@ -189,4 +233,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/DbString.output.cs b/test/Dapper.AOT.Test/Interceptors/DbString.output.cs index a935249..6dc257f 100644 --- a/test/Dapper.AOT.Test/Interceptors/DbString.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/DbString.output.cs @@ -249,4 +249,23 @@ public static void ConfigureDbStringDbParameter( dbParameter.Value = dbString.Value as object ?? global::System.DBNull.Value; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/DbString.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/DbString.output.netfx.cs index a935249..221e593 100644 --- a/test/Dapper.AOT.Test/Interceptors/DbString.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/DbString.output.netfx.cs @@ -249,4 +249,30 @@ public static void ConfigureDbStringDbParameter( dbParameter.Value = dbString.Value as object ?? global::System.DBNull.Value; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/DbValueUsage.output.cs b/test/Dapper.AOT.Test/Interceptors/DbValueUsage.output.cs index 4964982..044210b 100644 --- a/test/Dapper.AOT.Test/Interceptors/DbValueUsage.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/DbValueUsage.output.cs @@ -90,4 +90,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/DbValueUsage.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/DbValueUsage.output.netfx.cs index 4964982..90def68 100644 --- a/test/Dapper.AOT.Test/Interceptors/DbValueUsage.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/DbValueUsage.output.netfx.cs @@ -90,4 +90,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/DynamicMember.output.cs b/test/Dapper.AOT.Test/Interceptors/DynamicMember.output.cs index b4c85a5..e980e2e 100644 --- a/test/Dapper.AOT.Test/Interceptors/DynamicMember.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/DynamicMember.output.cs @@ -114,4 +114,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/DynamicMember.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/DynamicMember.output.netfx.cs index b4c85a5..d93fa94 100644 --- a/test/Dapper.AOT.Test/Interceptors/DynamicMember.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/DynamicMember.output.netfx.cs @@ -114,4 +114,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/EnumerableExtensions.output.cs b/test/Dapper.AOT.Test/Interceptors/EnumerableExtensions.output.cs index 942f882..6fecc3e 100644 --- a/test/Dapper.AOT.Test/Interceptors/EnumerableExtensions.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/EnumerableExtensions.output.cs @@ -62,4 +62,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/EnumerableExtensions.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/EnumerableExtensions.output.netfx.cs index 942f882..73328cd 100644 --- a/test/Dapper.AOT.Test/Interceptors/EnumerableExtensions.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/EnumerableExtensions.output.netfx.cs @@ -62,4 +62,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Execute.output.cs b/test/Dapper.AOT.Test/Interceptors/Execute.output.cs index b70dfd3..fcab75b 100644 --- a/test/Dapper.AOT.Test/Interceptors/Execute.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/Execute.output.cs @@ -154,4 +154,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Execute.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/Execute.output.netfx.cs index b70dfd3..56ec225 100644 --- a/test/Dapper.AOT.Test/Interceptors/Execute.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/Execute.output.netfx.cs @@ -154,4 +154,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/ExecuteBatch.output.cs b/test/Dapper.AOT.Test/Interceptors/ExecuteBatch.output.cs index 0175214..8cefcf0 100644 --- a/test/Dapper.AOT.Test/Interceptors/ExecuteBatch.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/ExecuteBatch.output.cs @@ -270,4 +270,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/ExecuteBatch.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/ExecuteBatch.output.netfx.cs index 0175214..be638eb 100644 --- a/test/Dapper.AOT.Test/Interceptors/ExecuteBatch.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/ExecuteBatch.output.netfx.cs @@ -270,4 +270,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/ExecuteScalar.output.cs b/test/Dapper.AOT.Test/Interceptors/ExecuteScalar.output.cs index 2f68b2f..b6cdde1 100644 --- a/test/Dapper.AOT.Test/Interceptors/ExecuteScalar.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/ExecuteScalar.output.cs @@ -236,4 +236,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/ExecuteScalar.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/ExecuteScalar.output.netfx.cs index 2f68b2f..a50f3b6 100644 --- a/test/Dapper.AOT.Test/Interceptors/ExecuteScalar.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/ExecuteScalar.output.netfx.cs @@ -236,4 +236,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/GetRowParser.output.cs b/test/Dapper.AOT.Test/Interceptors/GetRowParser.output.cs index ae7dcb1..602f357 100644 --- a/test/Dapper.AOT.Test/Interceptors/GetRowParser.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/GetRowParser.output.cs @@ -122,4 +122,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/GetRowParser.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/GetRowParser.output.netfx.cs index ae7dcb1..fb15ea2 100644 --- a/test/Dapper.AOT.Test/Interceptors/GetRowParser.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/GetRowParser.output.netfx.cs @@ -122,4 +122,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs index f3df746..78ec8c1 100644 --- a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs @@ -142,4 +142,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs index f3df746..32605c9 100644 --- a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs @@ -142,4 +142,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/IncludeSqlSource.output.cs b/test/Dapper.AOT.Test/Interceptors/IncludeSqlSource.output.cs index a4ec6b1..d765d4a 100644 --- a/test/Dapper.AOT.Test/Interceptors/IncludeSqlSource.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/IncludeSqlSource.output.cs @@ -55,4 +55,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/IncludeSqlSource.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/IncludeSqlSource.output.netfx.cs index a4ec6b1..b4fc37b 100644 --- a/test/Dapper.AOT.Test/Interceptors/IncludeSqlSource.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/IncludeSqlSource.output.netfx.cs @@ -55,4 +55,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/InheritedMembers.output.cs b/test/Dapper.AOT.Test/Interceptors/InheritedMembers.output.cs index 06c4243..f82c50b 100644 --- a/test/Dapper.AOT.Test/Interceptors/InheritedMembers.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/InheritedMembers.output.cs @@ -197,4 +197,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/InheritedMembers.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/InheritedMembers.output.netfx.cs index 06c4243..842270e 100644 --- a/test/Dapper.AOT.Test/Interceptors/InheritedMembers.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/InheritedMembers.output.netfx.cs @@ -197,4 +197,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/ListExpansion.output.cs b/test/Dapper.AOT.Test/Interceptors/ListExpansion.output.cs index 41e198b..1a856b4 100644 --- a/test/Dapper.AOT.Test/Interceptors/ListExpansion.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/ListExpansion.output.cs @@ -80,7 +80,21 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var typed = Cast(args, static () => new { ids = default(int[])! }); // expected shape var ps = cmd.Parameters; #pragma warning disable CS0618 // list-expansion: this *is* the library usage - global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + _ = global::Dapper.SqlMapper.LookupDbType(typeof(int[]), "ids", false, out var typeHandlerids); + // a runtime type-handler for the collection type wins over expansion, + // which is the order vanilla's own decision procedure applies + if (typeHandlerids is not null) + { + var hp = cmd.CreateParameter(); + hp.ParameterName = "ids"; + hp.Direction = global::System.Data.ParameterDirection.Input; + typeHandlerids.SetValue(hp, (object?)typed.ids ?? global::System.DBNull.Value); + ps.Add(hp); + } + else + { + global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + } #pragma warning restore CS0618 } @@ -102,7 +116,21 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var ps = cmd.Parameters; global::System.Data.Common.DbParameter p; #pragma warning disable CS0618 // list-expansion: this *is* the library usage - global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + _ = global::Dapper.SqlMapper.LookupDbType(typeof(global::System.Collections.Generic.List), "ids", false, out var typeHandlerids); + // a runtime type-handler for the collection type wins over expansion, + // which is the order vanilla's own decision procedure applies + if (typeHandlerids is not null) + { + var hp = cmd.CreateParameter(); + hp.ParameterName = "ids"; + hp.Direction = global::System.Data.ParameterDirection.Input; + typeHandlerids.SetValue(hp, (object?)typed.ids ?? global::System.DBNull.Value); + ps.Add(hp); + } + else + { + global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + } #pragma warning restore CS0618 p = cmd.CreateParameter(); @@ -131,7 +159,21 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var typed = Cast(args, static () => new { names = default(string[])! }); // expected shape var ps = cmd.Parameters; #pragma warning disable CS0618 // list-expansion: this *is* the library usage - global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "names", typed.names); + _ = global::Dapper.SqlMapper.LookupDbType(typeof(string[]), "names", false, out var typeHandlernames); + // a runtime type-handler for the collection type wins over expansion, + // which is the order vanilla's own decision procedure applies + if (typeHandlernames is not null) + { + var hp = cmd.CreateParameter(); + hp.ParameterName = "names"; + hp.Direction = global::System.Data.ParameterDirection.Input; + typeHandlernames.SetValue(hp, (object?)typed.names ?? global::System.DBNull.Value); + ps.Add(hp); + } + else + { + global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "names", typed.names); + } #pragma warning restore CS0618 } @@ -163,4 +205,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/ListExpansion.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/ListExpansion.output.netfx.cs index 41e198b..a709913 100644 --- a/test/Dapper.AOT.Test/Interceptors/ListExpansion.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/ListExpansion.output.netfx.cs @@ -80,7 +80,21 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var typed = Cast(args, static () => new { ids = default(int[])! }); // expected shape var ps = cmd.Parameters; #pragma warning disable CS0618 // list-expansion: this *is* the library usage - global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + _ = global::Dapper.SqlMapper.LookupDbType(typeof(int[]), "ids", false, out var typeHandlerids); + // a runtime type-handler for the collection type wins over expansion, + // which is the order vanilla's own decision procedure applies + if (typeHandlerids is not null) + { + var hp = cmd.CreateParameter(); + hp.ParameterName = "ids"; + hp.Direction = global::System.Data.ParameterDirection.Input; + typeHandlerids.SetValue(hp, (object?)typed.ids ?? global::System.DBNull.Value); + ps.Add(hp); + } + else + { + global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + } #pragma warning restore CS0618 } @@ -102,7 +116,21 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var ps = cmd.Parameters; global::System.Data.Common.DbParameter p; #pragma warning disable CS0618 // list-expansion: this *is* the library usage - global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + _ = global::Dapper.SqlMapper.LookupDbType(typeof(global::System.Collections.Generic.List), "ids", false, out var typeHandlerids); + // a runtime type-handler for the collection type wins over expansion, + // which is the order vanilla's own decision procedure applies + if (typeHandlerids is not null) + { + var hp = cmd.CreateParameter(); + hp.ParameterName = "ids"; + hp.Direction = global::System.Data.ParameterDirection.Input; + typeHandlerids.SetValue(hp, (object?)typed.ids ?? global::System.DBNull.Value); + ps.Add(hp); + } + else + { + global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + } #pragma warning restore CS0618 p = cmd.CreateParameter(); @@ -131,7 +159,21 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var typed = Cast(args, static () => new { names = default(string[])! }); // expected shape var ps = cmd.Parameters; #pragma warning disable CS0618 // list-expansion: this *is* the library usage - global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "names", typed.names); + _ = global::Dapper.SqlMapper.LookupDbType(typeof(string[]), "names", false, out var typeHandlernames); + // a runtime type-handler for the collection type wins over expansion, + // which is the order vanilla's own decision procedure applies + if (typeHandlernames is not null) + { + var hp = cmd.CreateParameter(); + hp.ParameterName = "names"; + hp.Direction = global::System.Data.ParameterDirection.Input; + typeHandlernames.SetValue(hp, (object?)typed.names ?? global::System.DBNull.Value); + ps.Add(hp); + } + else + { + global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "names", typed.names); + } #pragma warning restore CS0618 } @@ -163,4 +205,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/LiteralTokens.output.cs b/test/Dapper.AOT.Test/Interceptors/LiteralTokens.output.cs index a5f13b2..6482221 100644 --- a/test/Dapper.AOT.Test/Interceptors/LiteralTokens.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/LiteralTokens.output.cs @@ -85,4 +85,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/LiteralTokens.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/LiteralTokens.output.netfx.cs index a5f13b2..1981098 100644 --- a/test/Dapper.AOT.Test/Interceptors/LiteralTokens.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/LiteralTokens.output.netfx.cs @@ -85,4 +85,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/MappedSqlDetection.output.cs b/test/Dapper.AOT.Test/Interceptors/MappedSqlDetection.output.cs index e4759ba..d38ee4c 100644 --- a/test/Dapper.AOT.Test/Interceptors/MappedSqlDetection.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/MappedSqlDetection.output.cs @@ -193,4 +193,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/MappedSqlDetection.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/MappedSqlDetection.output.netfx.cs index e4759ba..827ea48 100644 --- a/test/Dapper.AOT.Test/Interceptors/MappedSqlDetection.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/MappedSqlDetection.output.netfx.cs @@ -193,4 +193,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/MiscDiagnostics.output.cs b/test/Dapper.AOT.Test/Interceptors/MiscDiagnostics.output.cs index 7585f73..c1ad90d 100644 --- a/test/Dapper.AOT.Test/Interceptors/MiscDiagnostics.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/MiscDiagnostics.output.cs @@ -367,4 +367,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/MiscDiagnostics.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/MiscDiagnostics.output.netfx.cs index 7585f73..b2a2148 100644 --- a/test/Dapper.AOT.Test/Interceptors/MiscDiagnostics.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/MiscDiagnostics.output.netfx.cs @@ -367,4 +367,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/NonConstant.output.cs b/test/Dapper.AOT.Test/Interceptors/NonConstant.output.cs index 48949b1..f64fe5b 100644 --- a/test/Dapper.AOT.Test/Interceptors/NonConstant.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/NonConstant.output.cs @@ -140,4 +140,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/NonConstant.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/NonConstant.output.netfx.cs index 48949b1..b4e1b0e 100644 --- a/test/Dapper.AOT.Test/Interceptors/NonConstant.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/NonConstant.output.netfx.cs @@ -140,4 +140,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/NonFactoryMethod.output.cs b/test/Dapper.AOT.Test/Interceptors/NonFactoryMethod.output.cs index cdc7f27..4d7b6a5 100644 --- a/test/Dapper.AOT.Test/Interceptors/NonFactoryMethod.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/NonFactoryMethod.output.cs @@ -363,4 +363,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/NonFactoryMethod.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/NonFactoryMethod.output.netfx.cs index cdc7f27..0f3861a 100644 --- a/test/Dapper.AOT.Test/Interceptors/NonFactoryMethod.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/NonFactoryMethod.output.netfx.cs @@ -363,4 +363,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/OmitAttribute.output.cs b/test/Dapper.AOT.Test/Interceptors/OmitAttribute.output.cs index 41deee3..365824f 100644 --- a/test/Dapper.AOT.Test/Interceptors/OmitAttribute.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/OmitAttribute.output.cs @@ -38,4 +38,23 @@ private class CommonCommandFactory : global::Dapper.CommandFactory } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/OmitAttribute.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/OmitAttribute.output.netfx.cs index 41deee3..c4220ee 100644 --- a/test/Dapper.AOT.Test/Interceptors/OmitAttribute.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/OmitAttribute.output.netfx.cs @@ -38,4 +38,30 @@ private class CommonCommandFactory : global::Dapper.CommandFactory } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Query.output.cs b/test/Dapper.AOT.Test/Interceptors/Query.output.cs index 9fec975..c46acae 100644 --- a/test/Dapper.AOT.Test/Interceptors/Query.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/Query.output.cs @@ -304,4 +304,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Query.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/Query.output.netfx.cs index f39237c..a3ea61f 100644 --- a/test/Dapper.AOT.Test/Interceptors/Query.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/Query.output.netfx.cs @@ -276,4 +276,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithConstructor.output.cs b/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithConstructor.output.cs index df82c4d..2797b51 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithConstructor.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithConstructor.output.cs @@ -1012,4 +1012,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithConstructor.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithConstructor.output.netfx.cs index df82c4d..cf376f3 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithConstructor.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithConstructor.output.netfx.cs @@ -1012,4 +1012,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithFactoryMethod.output.cs b/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithFactoryMethod.output.cs index 2690c41..b43222c 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithFactoryMethod.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithFactoryMethod.output.cs @@ -363,4 +363,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithFactoryMethod.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithFactoryMethod.output.netfx.cs index 2690c41..e5abf68 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithFactoryMethod.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryCustomConstructionWithFactoryMethod.output.netfx.cs @@ -363,4 +363,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryDetection.output.cs b/test/Dapper.AOT.Test/Interceptors/QueryDetection.output.cs index 3a49981..ca540b6 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryDetection.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryDetection.output.cs @@ -224,4 +224,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryDetection.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/QueryDetection.output.netfx.cs index 3a49981..19875ca 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryDetection.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryDetection.output.netfx.cs @@ -224,4 +224,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryEnumerableParams.output.cs b/test/Dapper.AOT.Test/Interceptors/QueryEnumerableParams.output.cs index 1bc3a71..4575e15 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryEnumerableParams.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryEnumerableParams.output.cs @@ -123,4 +123,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryEnumerableParams.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/QueryEnumerableParams.output.netfx.cs index 1bc3a71..134fda4 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryEnumerableParams.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryEnumerableParams.output.netfx.cs @@ -123,4 +123,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryNonGeneric.output.cs b/test/Dapper.AOT.Test/Interceptors/QueryNonGeneric.output.cs index 56eb956..b6c83a0 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryNonGeneric.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryNonGeneric.output.cs @@ -337,4 +337,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryNonGeneric.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/QueryNonGeneric.output.netfx.cs index 8dccf53..76d6a78 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryNonGeneric.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryNonGeneric.output.netfx.cs @@ -311,4 +311,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryPrimitive.output.cs b/test/Dapper.AOT.Test/Interceptors/QueryPrimitive.output.cs index 56a18c0..ec58fb2 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryPrimitive.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryPrimitive.output.cs @@ -322,4 +322,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryPrimitive.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/QueryPrimitive.output.netfx.cs index afe89a4..7d7d94c 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryPrimitive.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryPrimitive.output.netfx.cs @@ -283,4 +283,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryStrictBind.output.cs b/test/Dapper.AOT.Test/Interceptors/QueryStrictBind.output.cs index 34e4571..0fd819e 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryStrictBind.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryStrictBind.output.cs @@ -321,4 +321,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryStrictBind.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/QueryStrictBind.output.netfx.cs index 34e4571..ae0715c 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryStrictBind.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryStrictBind.output.netfx.cs @@ -321,4 +321,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryUntyped.output.cs b/test/Dapper.AOT.Test/Interceptors/QueryUntyped.output.cs index dac9ec5..d770d4c 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryUntyped.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryUntyped.output.cs @@ -469,4 +469,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/QueryUntyped.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/QueryUntyped.output.netfx.cs index 09e8f55..296e6de 100644 --- a/test/Dapper.AOT.Test/Interceptors/QueryUntyped.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/QueryUntyped.output.netfx.cs @@ -413,4 +413,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/RequiredProperties.output.cs b/test/Dapper.AOT.Test/Interceptors/RequiredProperties.output.cs index 063e3ab..0a7ffd2 100644 --- a/test/Dapper.AOT.Test/Interceptors/RequiredProperties.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/RequiredProperties.output.cs @@ -162,4 +162,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/RequiredProperties.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/RequiredProperties.output.netfx.cs index 063e3ab..20e97e3 100644 --- a/test/Dapper.AOT.Test/Interceptors/RequiredProperties.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/RequiredProperties.output.netfx.cs @@ -162,4 +162,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/RowCountHint.output.cs b/test/Dapper.AOT.Test/Interceptors/RowCountHint.output.cs index c6165e5..3660491 100644 --- a/test/Dapper.AOT.Test/Interceptors/RowCountHint.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/RowCountHint.output.cs @@ -223,4 +223,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/RowCountHint.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/RowCountHint.output.netfx.cs index c6165e5..ad108a7 100644 --- a/test/Dapper.AOT.Test/Interceptors/RowCountHint.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/RowCountHint.output.netfx.cs @@ -223,4 +223,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Single.output.cs b/test/Dapper.AOT.Test/Interceptors/Single.output.cs index 635767a..2fe6dd6 100644 --- a/test/Dapper.AOT.Test/Interceptors/Single.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/Single.output.cs @@ -287,4 +287,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Single.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/Single.output.netfx.cs index 635767a..97963e2 100644 --- a/test/Dapper.AOT.Test/Interceptors/Single.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/Single.output.netfx.cs @@ -287,4 +287,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/SqlDetection.output.cs b/test/Dapper.AOT.Test/Interceptors/SqlDetection.output.cs index 53572ea..811cbd9 100644 --- a/test/Dapper.AOT.Test/Interceptors/SqlDetection.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/SqlDetection.output.cs @@ -145,4 +145,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/SqlDetection.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/SqlDetection.output.netfx.cs index 53572ea..494eadf 100644 --- a/test/Dapper.AOT.Test/Interceptors/SqlDetection.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/SqlDetection.output.netfx.cs @@ -145,4 +145,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/SqlParse.output.cs b/test/Dapper.AOT.Test/Interceptors/SqlParse.output.cs index 09a31fc..f706074 100644 --- a/test/Dapper.AOT.Test/Interceptors/SqlParse.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/SqlParse.output.cs @@ -148,4 +148,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/SqlParse.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/SqlParse.output.netfx.cs index 09a31fc..10ee9fe 100644 --- a/test/Dapper.AOT.Test/Interceptors/SqlParse.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/SqlParse.output.netfx.cs @@ -148,4 +148,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Techempower.output.cs b/test/Dapper.AOT.Test/Interceptors/Techempower.output.cs index 2377f02..42b75ad 100644 --- a/test/Dapper.AOT.Test/Interceptors/Techempower.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/Techempower.output.cs @@ -203,4 +203,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/Techempower.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/Techempower.output.netfx.cs index 2377f02..f953b88 100644 --- a/test/Dapper.AOT.Test/Interceptors/Techempower.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/Techempower.output.netfx.cs @@ -203,4 +203,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.cs b/test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.cs index 83e5bfe..d34f15b 100644 --- a/test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.cs @@ -113,4 +113,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.netfx.cs index 83e5bfe..bc1a724 100644 --- a/test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.netfx.cs @@ -113,4 +113,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/TsqlTips.output.cs b/test/Dapper.AOT.Test/Interceptors/TsqlTips.output.cs index 0bdef03..188066e 100644 --- a/test/Dapper.AOT.Test/Interceptors/TsqlTips.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/TsqlTips.output.cs @@ -288,7 +288,21 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var typed = Cast(args, static () => new { ids = default(int[])! }); // expected shape var ps = cmd.Parameters; #pragma warning disable CS0618 // list-expansion: this *is* the library usage - global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + _ = global::Dapper.SqlMapper.LookupDbType(typeof(int[]), "ids", false, out var typeHandlerids); + // a runtime type-handler for the collection type wins over expansion, + // which is the order vanilla's own decision procedure applies + if (typeHandlerids is not null) + { + var hp = cmd.CreateParameter(); + hp.ParameterName = "ids"; + hp.Direction = global::System.Data.ParameterDirection.Input; + typeHandlerids.SetValue(hp, (object?)typed.ids ?? global::System.DBNull.Value); + ps.Add(hp); + } + else + { + global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + } #pragma warning restore CS0618 } @@ -327,4 +341,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/TsqlTips.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/TsqlTips.output.netfx.cs index 0bdef03..04ed43a 100644 --- a/test/Dapper.AOT.Test/Interceptors/TsqlTips.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/TsqlTips.output.netfx.cs @@ -288,7 +288,21 @@ public override void AddParameters(in global::Dapper.UnifiedCommand cmd, object? var typed = Cast(args, static () => new { ids = default(int[])! }); // expected shape var ps = cmd.Parameters; #pragma warning disable CS0618 // list-expansion: this *is* the library usage - global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + _ = global::Dapper.SqlMapper.LookupDbType(typeof(int[]), "ids", false, out var typeHandlerids); + // a runtime type-handler for the collection type wins over expansion, + // which is the order vanilla's own decision procedure applies + if (typeHandlerids is not null) + { + var hp = cmd.CreateParameter(); + hp.ParameterName = "ids"; + hp.Direction = global::System.Data.ParameterDirection.Input; + typeHandlerids.SetValue(hp, (object?)typed.ids ?? global::System.DBNull.Value); + ps.Add(hp); + } + else + { + global::Dapper.SqlMapper.PackListParameters(cmd.Command!, "ids", typed.ids); + } #pragma warning restore CS0618 } @@ -327,4 +341,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.input.cs b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.input.cs new file mode 100644 index 0000000..71b54cd --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.input.cs @@ -0,0 +1,31 @@ +using Dapper; +using System.Data.Common; + +[module: DapperAot] + +public static class Foo +{ + static void SomeCode(DbConnection connection) + { + // an unrecognized member type defers to vanilla's decision procedure at execution + // time: a runtime SqlMapper.AddTypeHandler registration binds via the handler, and + // otherwise the value binds raw exactly as before (modern providers handle types + // vanilla's map does not) + _ = connection.Execute("insert Events (At, Name) values (@At, @Name)", new EventRow { At = new LocalDate { Year = 2026, Month = 8, Day = 20 }, Name = "x" }); + + // reads resolve handlers through the flexible path; nothing changes in the emit here + _ = connection.Query("select At, Name from Events"); + } + + public class LocalDate + { + public int Year { get; set; } + public int Month { get; set; } + public int Day { get; set; } + } + public class EventRow + { + public LocalDate At { get; set; } + public string Name { get; set; } + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.cs b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.cs new file mode 100644 index 0000000..d613588 --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.cs @@ -0,0 +1,203 @@ +#nullable enable +#pragma warning disable IDE0078 // unnecessary suppression is necessary +#pragma warning disable CS9270 // SDK-dependent change to interceptors usage +namespace Dapper.AOT // interceptors must be in a known namespace +{ + file static class DapperGeneratedInterceptors + { + [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\TypeHandlerDispatch.input.cs", 14, 24)] + internal static int Execute0(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType) + { + // Execute, HasParameters, Text, KnownParameters + // takes parameter: global::Foo.EventRow + // parameter map: At Name + global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql)); + global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.Text); + global::System.Diagnostics.Debug.Assert(param is not null); + + return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.Text, commandTimeout.GetValueOrDefault(), CommandFactory0.Instance).Execute((global::Foo.EventRow)param!); + + } + + [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\TypeHandlerDispatch.input.cs", 17, 24)] + internal static global::System.Collections.Generic.IEnumerable Query1(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, bool buffered, int? commandTimeout, global::System.Data.CommandType? commandType) + { + // Query, TypedResult, Buffered, Text, BindResultsByName + // returns data: global::Foo.EventRow + global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql)); + global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.Text); + global::System.Diagnostics.Debug.Assert(buffered is true); + global::System.Diagnostics.Debug.Assert(param is null); + + return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.Text, commandTimeout.GetValueOrDefault(), DefaultCommandFactory).QueryBuffered(param, RowFactory0.Instance); + + } + + private class CommonCommandFactory : global::Dapper.CommandFactory + { + public override global::System.Data.Common.DbCommand GetCommand(global::System.Data.Common.DbConnection connection, string sql, global::System.Data.CommandType commandType, T args) + { + var cmd = base.GetCommand(connection, sql, commandType, args); + // apply special per-provider command initialization logic for OracleCommand + if (cmd is global::Oracle.ManagedDataAccess.Client.OracleCommand cmd0) + { + cmd0.BindByName = true; + cmd0.InitialLONGFetchSize = -1; + + } + return cmd; + } + + } + + private static readonly CommonCommandFactory DefaultCommandFactory = new(); + + private sealed class RowFactory0 : global::Dapper.RowFactory + { + internal static readonly RowFactory0 Instance = new(); + private RowFactory0() {} + public override object? Tokenize(global::System.Data.Common.DbDataReader reader, global::System.Span tokens, int columnOffset) + { + for (int i = 0; i < tokens.Length; i++) + { + int token = -1; + var name = reader.GetName(columnOffset); + var type = reader.GetFieldType(columnOffset); + switch (NormalizedHash(name)) + { + case 1462048136U when NormalizedEquals(name, "at"): + token = type == typeof(global::Foo.LocalDate) ? 0 : 2; // two tokens for right-typed and type-flexible + break; + case 2369371622U when NormalizedEquals(name, "name"): + token = type == typeof(string) ? 1 : 3; + break; + + } + tokens[i] = token; + columnOffset++; + + } + return null; + } + public override global::Foo.EventRow Read(global::System.Data.Common.DbDataReader reader, global::System.ReadOnlySpan tokens, int columnOffset, object? state) + { + global::Foo.EventRow result = new(); + foreach (var token in tokens) + { + switch (token) + { + case 0: + result.At = reader.IsDBNull(columnOffset) ? (global::Foo.LocalDate?)null : reader.GetFieldValue(columnOffset); + break; + case 2: + result.At = reader.IsDBNull(columnOffset) ? (global::Foo.LocalDate?)null : GetValue(reader, columnOffset); + break; + case 1: + result.Name = reader.IsDBNull(columnOffset) ? (string?)null : reader.GetString(columnOffset); + break; + case 3: + result.Name = reader.IsDBNull(columnOffset) ? (string?)null : GetValue(reader, columnOffset); + break; + + } + columnOffset++; + + } + return result; + + } + + } + + private sealed class CommandFactory0 : CommonCommandFactory + { + internal static readonly CommandFactory0 Instance = new(); + public override void AddParameters(in global::Dapper.UnifiedCommand cmd, global::Foo.EventRow args) + { + var ps = cmd.Parameters; + global::System.Data.Common.DbParameter p; + #pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + var dbTypeAt = global::Dapper.SqlMapper.LookupDbType(typeof(global::Foo.LocalDate), "At", false, out var typeHandlerAt); + #pragma warning restore CS0618 + p = cmd.CreateParameter(); + p.ParameterName = "At"; + p.Direction = global::System.Data.ParameterDirection.Input; + if (typeHandlerAt is not null) + { + typeHandlerAt.SetValue(p, (object?)args.At ?? global::System.DBNull.Value); + } + else + { + if (dbTypeAt is not null) p.DbType = dbTypeAt.GetValueOrDefault(); + p.Value = AsValue(args.At); + + } + ps.Add(p); + + p = cmd.CreateParameter(); + p.ParameterName = "Name"; + p.DbType = global::System.Data.DbType.String; + p.Direction = global::System.Data.ParameterDirection.Input; + SetValueWithDefaultSize(p, args.Name); + ps.Add(p); + + } + public override void UpdateParameters(in global::Dapper.UnifiedCommand cmd, global::Foo.EventRow args) + { + var ps = cmd.Parameters; + #pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(typeof(global::Foo.LocalDate), "At", false, out var typeHandlerAt); + #pragma warning restore CS0618 + if (typeHandlerAt is not null) + { + typeHandlerAt.SetValue(ps[0], (object?)args.At ?? global::System.DBNull.Value); + } + else + { + ps[0].Value = AsValue(args.At); + } + ps[1].Value = AsValue(args.Name); + + } + + } + + + } +} +namespace System.Runtime.CompilerServices +{ + // this type is needed by the compiler to implement interceptors - it doesn't need to + // come from the runtime itself, though + + [global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate + [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] + sealed file class InterceptsLocationAttribute : global::System.Attribute + { + public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber) + { + _ = path; + _ = lineNumber; + _ = columnNumber; + } + } +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.netfx.cs new file mode 100644 index 0000000..08158aa --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.netfx.cs @@ -0,0 +1,210 @@ +#nullable enable +#pragma warning disable IDE0078 // unnecessary suppression is necessary +#pragma warning disable CS9270 // SDK-dependent change to interceptors usage +namespace Dapper.AOT // interceptors must be in a known namespace +{ + file static class DapperGeneratedInterceptors + { + [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\TypeHandlerDispatch.input.cs", 14, 24)] + internal static int Execute0(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType) + { + // Execute, HasParameters, Text, KnownParameters + // takes parameter: global::Foo.EventRow + // parameter map: At Name + global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql)); + global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.Text); + global::System.Diagnostics.Debug.Assert(param is not null); + + return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.Text, commandTimeout.GetValueOrDefault(), CommandFactory0.Instance).Execute((global::Foo.EventRow)param!); + + } + + [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\TypeHandlerDispatch.input.cs", 17, 24)] + internal static global::System.Collections.Generic.IEnumerable Query1(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, bool buffered, int? commandTimeout, global::System.Data.CommandType? commandType) + { + // Query, TypedResult, Buffered, Text, BindResultsByName + // returns data: global::Foo.EventRow + global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql)); + global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.Text); + global::System.Diagnostics.Debug.Assert(buffered is true); + global::System.Diagnostics.Debug.Assert(param is null); + + return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.Text, commandTimeout.GetValueOrDefault(), DefaultCommandFactory).QueryBuffered(param, RowFactory0.Instance); + + } + + private class CommonCommandFactory : global::Dapper.CommandFactory + { + public override global::System.Data.Common.DbCommand GetCommand(global::System.Data.Common.DbConnection connection, string sql, global::System.Data.CommandType commandType, T args) + { + var cmd = base.GetCommand(connection, sql, commandType, args); + // apply special per-provider command initialization logic for OracleCommand + if (cmd is global::Oracle.ManagedDataAccess.Client.OracleCommand cmd0) + { + cmd0.BindByName = true; + cmd0.InitialLONGFetchSize = -1; + + } + return cmd; + } + + } + + private static readonly CommonCommandFactory DefaultCommandFactory = new(); + + private sealed class RowFactory0 : global::Dapper.RowFactory + { + internal static readonly RowFactory0 Instance = new(); + private RowFactory0() {} + public override object? Tokenize(global::System.Data.Common.DbDataReader reader, global::System.Span tokens, int columnOffset) + { + for (int i = 0; i < tokens.Length; i++) + { + int token = -1; + var name = reader.GetName(columnOffset); + var type = reader.GetFieldType(columnOffset); + switch (NormalizedHash(name)) + { + case 1462048136U when NormalizedEquals(name, "at"): + token = type == typeof(global::Foo.LocalDate) ? 0 : 2; // two tokens for right-typed and type-flexible + break; + case 2369371622U when NormalizedEquals(name, "name"): + token = type == typeof(string) ? 1 : 3; + break; + + } + tokens[i] = token; + columnOffset++; + + } + return null; + } + public override global::Foo.EventRow Read(global::System.Data.Common.DbDataReader reader, global::System.ReadOnlySpan tokens, int columnOffset, object? state) + { + global::Foo.EventRow result = new(); + foreach (var token in tokens) + { + switch (token) + { + case 0: + result.At = reader.IsDBNull(columnOffset) ? (global::Foo.LocalDate?)null : reader.GetFieldValue(columnOffset); + break; + case 2: + result.At = reader.IsDBNull(columnOffset) ? (global::Foo.LocalDate?)null : GetValue(reader, columnOffset); + break; + case 1: + result.Name = reader.IsDBNull(columnOffset) ? (string?)null : reader.GetString(columnOffset); + break; + case 3: + result.Name = reader.IsDBNull(columnOffset) ? (string?)null : GetValue(reader, columnOffset); + break; + + } + columnOffset++; + + } + return result; + + } + + } + + private sealed class CommandFactory0 : CommonCommandFactory + { + internal static readonly CommandFactory0 Instance = new(); + public override void AddParameters(in global::Dapper.UnifiedCommand cmd, global::Foo.EventRow args) + { + var ps = cmd.Parameters; + global::System.Data.Common.DbParameter p; + #pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + var dbTypeAt = global::Dapper.SqlMapper.LookupDbType(typeof(global::Foo.LocalDate), "At", false, out var typeHandlerAt); + #pragma warning restore CS0618 + p = cmd.CreateParameter(); + p.ParameterName = "At"; + p.Direction = global::System.Data.ParameterDirection.Input; + if (typeHandlerAt is not null) + { + typeHandlerAt.SetValue(p, (object?)args.At ?? global::System.DBNull.Value); + } + else + { + if (dbTypeAt is not null) p.DbType = dbTypeAt.GetValueOrDefault(); + p.Value = AsValue(args.At); + + } + ps.Add(p); + + p = cmd.CreateParameter(); + p.ParameterName = "Name"; + p.DbType = global::System.Data.DbType.String; + p.Direction = global::System.Data.ParameterDirection.Input; + SetValueWithDefaultSize(p, args.Name); + ps.Add(p); + + } + public override void UpdateParameters(in global::Dapper.UnifiedCommand cmd, global::Foo.EventRow args) + { + var ps = cmd.Parameters; + #pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(typeof(global::Foo.LocalDate), "At", false, out var typeHandlerAt); + #pragma warning restore CS0618 + if (typeHandlerAt is not null) + { + typeHandlerAt.SetValue(ps[0], (object?)args.At ?? global::System.DBNull.Value); + } + else + { + ps[0].Value = AsValue(args.At); + } + ps[1].Value = AsValue(args.Name); + + } + + } + + + } +} +namespace System.Runtime.CompilerServices +{ + // this type is needed by the compiler to implement interceptors - it doesn't need to + // come from the runtime itself, though + + [global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate + [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] + sealed file class InterceptsLocationAttribute : global::System.Attribute + { + public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber) + { + _ = path; + _ = lineNumber; + _ = columnNumber; + } + } +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.netfx.txt b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.netfx.txt new file mode 100644 index 0000000..6e02c00 --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.netfx.txt @@ -0,0 +1,4 @@ +Generator produced 1 diagnostics: + +Hidden DAP000 L1 C1 +Dapper.AOT handled 2 of 2 enabled call-sites (0 unsupported API, 0 skipped due to diagnostics) using 2 interceptors, 1 commands and 1 readers diff --git a/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.txt b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.txt new file mode 100644 index 0000000..6e02c00 --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/TypeHandlerDispatch.output.txt @@ -0,0 +1,4 @@ +Generator produced 1 diagnostics: + +Hidden DAP000 L1 C1 +Dapper.AOT handled 2 of 2 enabled call-sites (0 unsupported API, 0 skipped due to diagnostics) using 2 interceptors, 1 commands and 1 readers diff --git a/test/Dapper.AOT.Test/Interceptors/UnconstructableResults.output.cs b/test/Dapper.AOT.Test/Interceptors/UnconstructableResults.output.cs index fa63d7d..c9397c7 100644 --- a/test/Dapper.AOT.Test/Interceptors/UnconstructableResults.output.cs +++ b/test/Dapper.AOT.Test/Interceptors/UnconstructableResults.output.cs @@ -105,4 +105,23 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +} diff --git a/test/Dapper.AOT.Test/Interceptors/UnconstructableResults.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/UnconstructableResults.output.netfx.cs index fa63d7d..6795120 100644 --- a/test/Dapper.AOT.Test/Interceptors/UnconstructableResults.output.netfx.cs +++ b/test/Dapper.AOT.Test/Interceptors/UnconstructableResults.output.netfx.cs @@ -105,4 +105,30 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber _ = columnNumber; } } -} \ No newline at end of file +} +namespace System.Runtime.CompilerServices +{ + // down-level polyfill; the compiler matches this attribute by full name + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : global::System.Attribute { } +} + +namespace Dapper.Aot.Generated +{ + // installs the runtime type-handler bridge: SqlMapper.AddTypeHandler registrations reach + // Dapper.AOT's readers through these callbacks, compiled against *this* project's Dapper + // (which may be Dapper or Dapper.StrongName - the library cannot reference either) + file static class TypeHandlerBridgeInitializer + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Initialize() => global::Dapper.TypeHandlerBridge.Configure( + static type => global::Dapper.SqlMapper.HasTypeHandler(type), + static (type, value) => + { +#pragma warning disable CS0618 // vanilla's decision procedure: this *is* the library usage + _ = global::Dapper.SqlMapper.LookupDbType(type, "", false, out var handler); +#pragma warning restore CS0618 + return handler is null ? value : handler.Parse(type, value); + }); + } +}