diff --git a/notes/harness-baseline.md b/notes/harness-baseline.md index d3672230..4d087566 100644 --- a/notes/harness-baseline.md +++ b/notes/harness-baseline.md @@ -199,6 +199,22 @@ list expansion, TVPs, custom params), TypeHandlerTests ×16 (type-handler story) ×16 (coercions + tokens), Async/Literal (literals), plus the First-pipeline drain pair and the small tail. Nothing unexplained. +## Round 13: type handlers (PR #206) - 705/793 + +Runtime `SqlMapper.AddTypeHandler` registrations honored end-to-end by deferring to +vanilla's `LookupDbType` at execution time (writes) and a generated-code bridge into the +AOT readers (reads - the lib cannot reference Dapper without splitting the registry +against StrongName consumers). The whole runtime-handler family cleared, plus the +bare-DataTable TVP pair and Xml types for free (vanilla registers those handlers by +default). Full account: [typehandlers-design.md](typehandlers-design.md), including the +three probed contracts (DBNull-not-null to handlers; char excluded - StringFixedLength +pads; typeof needs TypeOfName) and the silent-harness-build-failure lesson. + +**705 passed / 88 failed.** Remaining: Misc x11 (privates/fields, inheritance, +Int16/Int32 + nullable-char coercions, message parity, multi-exec object[]), Literal x5 + +async x3, deferred-by-decision (AnsiString pair, SetTypeMap pair - see PR #206), BigInt +coercion, Constructor x2, singles. + ## Round 11: dynamic-record fidelity (PR #200) - 672/793 `DynamicRecord` diverged from vanilla's `DapperRow` three ways, all caught by the suite diff --git a/notes/parity.md b/notes/parity.md index 144f70cf..266f015a 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 new file mode 100644 index 00000000..9d9cdf81 --- /dev/null +++ b/notes/typehandlers-design.md @@ -0,0 +1,129 @@ +# 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. + +## 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. + +## Direction (agreed 2026-08-21): declarative config attributes as the primary spelling + +A static `Dapper.SomeConfigCall(...)` becomes `[module: SomeDapperConfig(...)]` - and that +is *better scoped*, not merely equivalent: per-assembly instead of process-global mutable +state, deterministic (no startup-ordering races), reviewable in the diff, and +compile-time-visible so the generator bakes it at zero runtime cost. The protobuf-net +precedent carries over whole, including the cross-assembly hand-off: the generator gathers +assembly-level declarations from *references*, so a package can ship handlers for the +types it owns (the [ProtoSurrogate] pattern, probed and shipped there). + +The config-call surface mapped onto attributes: + +| runtime call | declarative spelling | +| --- | --- | +| `SqlMapper.AddTypeHandler(typeof(T), h)` | `[module: TypeHandler]` - already ships (dormant); generator wires it, announced handlers *elide* the runtime dispatch for that type | +| `SqlMapper.AddTypeMap(type, dbType)` | `[module: TypeMap(typeof(string), DbType.AnsiString)]` (new) - also answers the deferred AnsiString pair with zero per-parameter cost | +| `Settings.*` globals (CommandTimeout, list-expansion knobs...) | `[module: DapperSettings(...)]`-style (new); several parity rows already wanted "a compile-time global" | +| `DefaultTypeMap.MatchNamesWithUnderscores` | same treatment (parity row already asks for it) | +| `SetTypeMap` / `CustomPropertyTypeMap` | stays 🚫; `[Column]` + `[UseColumnAttribute]` is the spelling | + +Layering (unchanged from the PR, sharpened by the discussion): + +1. tier 1 (PR #206) stays: runtime registrations keep working, and after the enum gate the + cost is confined to the people using the feature; +2. tier 2 attributes become the *recommended* spelling, statically dispatched; the + migration story is tooling, not docs alone - an analyzer that spots + `SqlMapper.AddTypeHandler(...)` in a [DapperAot] compilation and offers the attribute + as a code fix (the AotMigrationAnalyzer pattern from protobuf-net); +3. a strict switch turns the runtime bridge off entirely (closed world, trimmable) for + consumers who want the full protobuf-net posture. diff --git a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs index 1139de5c..a5201645 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs @@ -280,6 +280,12 @@ 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, + hasPreferTypeHandlersForEnums: compilation.GetTypeByMetadataName("Dapper.SqlMapper+Settings") is { } settings + && !settings.GetMembers("PreferTypeHandlersForEnums").IsEmpty, needsCommandPrep: needsCommandPrep, baseCommandFactoryName: baseFactory, baseFactoryCanConstruct: canConstruct, @@ -589,6 +595,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,11 +1347,99 @@ 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" + && (!member.IsEnum || ctx.Environment.HasPreferTypeHandlersForEnums)) + { + // 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; + if (member.IsEnum) + { + // enum handlers only apply under Settings.PreferTypeHandlersForEnums + // (vanilla checks the same); gating on the static bool means enum + // parameters pay no lookup unless the feature is actually in use + sb.Append("global::Dapper.SqlMapper.ITypeHandler? typeHandler").Append(suffix).Append(" = null;").NewLine() + .Append("if (global::Dapper.SqlMapper.Settings.PreferTypeHandlersForEnums)").Indent().NewLine() + .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 typeHandler").Append(suffix).Append(");").NewLine() + .Append("#pragma warning restore CS0618").Outdent().NewLine(); + } + else + { + 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(); + if (!member.IsEnum) + { + sb.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(); sb.Append("p.ParameterName = ").AppendVerbatimLiteral(member.DbName).Append(";").NewLine(); @@ -1419,6 +1525,52 @@ private static void WriteArgs(in GenerateState ctx, ParamPlan? parameterType, Co break; } + if (!member.HasDbType && !member.IsDbString && member.TypeOfName != "object" && member.TypeOfName != "char" + && (!member.IsEnum || ctx.Environment.HasPreferTypeHandlersForEnums)) + { + // mirror the Add-mode runtime dispatch; the parameter shape is stable + // (always exactly one), so command reuse stays legal + if (member.IsEnum) + { + sb.Append("global::Dapper.SqlMapper.ITypeHandler? typeHandler").Append(member.CodeName).Append(" = null;").NewLine() + .Append("if (global::Dapper.SqlMapper.Settings.PreferTypeHandlersForEnums)").Indent().NewLine() + .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 typeHandler").Append(member.CodeName).Append(");").NewLine() + .Append("#pragma warning restore CS0618").Outdent().NewLine(); + } + else + { + 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(); + } + sb.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 cf97fa0a..77cbed08 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,9 @@ internal sealed class InterceptorEnvironment : IEquatable] at module level, if any public bool BaseFactoryCanConstruct { get; } @@ -18,12 +21,16 @@ internal sealed class InterceptorEnvironment : IEquatable specialCommandTypes, ParamPlan systemObjectPlan) { AllowUnsafe = allowUnsafe; AssemblyName = assemblyName; HasInterceptsLocationAttribute = hasInterceptsLocationAttribute; + HasModuleInitializer = hasModuleInitializer; + HasVanillaTypeHandlers = hasVanillaTypeHandlers; + HasPreferTypeHandlersForEnums = hasPreferTypeHandlersForEnums; NeedsCommandPrep = needsCommandPrep; BaseCommandFactoryName = baseCommandFactoryName; BaseFactoryCanConstruct = baseFactoryCanConstruct; @@ -35,6 +42,9 @@ 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 + && HasPreferTypeHandlersForEnums == other.HasPreferTypeHandlersForEnums && 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 55eaf640..06b549b9 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/ParamPlan.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/Model/ParamPlan.cs @@ -162,11 +162,14 @@ 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 + public bool IsEnum { get; } // including Nullable 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, + bool isEnum) { IsMapped = isMapped; IsCancellation = isCancellation; @@ -185,13 +188,15 @@ private ParamMember(bool isMapped, bool isCancellation, bool isRowCount, string Precision = precision; Scale = scale; TypeName = typeName; + TypeOfName = typeOfName; + IsEnum = isEnum; } 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, "", "", false); } var dbType = member.GetDbType(out _); var size = member.TryGetValue("Size"); @@ -219,7 +224,10 @@ 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!)), + MakeNonNullable(member.CodeType!).TypeKind == TypeKind.Enum); } public bool Equals(ParamMember other) => IsMapped == other.IsMapped @@ -238,7 +246,9 @@ 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) + && IsEnum == other.IsEnum; 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 8de835cf..01c0f1c8 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 00000000..d8ea8f5f --- /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 00000000..9da70576 --- /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 dc540e71..fb1b339e 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 ea7c708d..32af9fbe 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 afc2ca64..d691288f 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 00000000..4de01a1f --- /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 7936f22c..4e0e4faa 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 7936f22c..ed51940d 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 42ed418c..3ded2eb0 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 42ed418c..768b3a9f 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 c8ca3231..a74dadab 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 c8ca3231..a7087318 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 0786934f..6d30df76 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 0786934f..dbe5002f 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 5e7b41f8..81b17d20 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 5e7b41f8..08e7d804 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 95e4a990..04c08efa 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 95e4a990..29ecefaa 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 04baf13c..bf852c68 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 04baf13c..69055ff1 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 dd032334..b9761d19 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 dd032334..55d58ff4 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 65050cd5..65690669 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 a9352496..6dc257fc 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 a9352496..221e5932 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 4964982c..044210b8 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 4964982c..90def686 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 b4c85a51..e980e2e4 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 b4c85a51..d93fa94e 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 942f8821..6fecc3ea 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 942f8821..73328cdb 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 b70dfd3d..fcab75b2 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 b70dfd3d..56ec2256 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 01752146..8cefcf07 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 01752146..be638eb2 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 2f68b2f3..b6cdde16 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 2f68b2f3..a50f3b61 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 ae7dcb16..602f3573 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 ae7dcb16..fb15ea2a 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 f3df7464..78ec8c1b 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 f3df7464..32605c99 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 a4ec6b1e..d765d4a7 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 a4ec6b1e..b4fc37b9 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 06c42433..f82c50b3 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 06c42433..842270ec 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 41e198b8..1a856b4b 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 41e198b8..a709913c 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 a5f13b23..64822218 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 a5f13b23..19810987 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 e4759ba8..d38ee4c0 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 e4759ba8..827ea486 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 7585f734..c1ad90d3 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 7585f734..b2a21482 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 48949b17..f64fe5b3 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 48949b17..b4e1b0e2 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 cdc7f275..4d7b6a51 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 cdc7f275..0f3861ad 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 41deee34..365824f7 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 41deee34..c4220eea 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 9fec9750..c46acae9 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 f39237c0..a3ea61f4 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 df82c4d3..2797b515 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 df82c4d3..cf376f33 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 2690c419..b43222c3 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 2690c419..e5abf685 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 3a49981c..ca540b61 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 3a49981c..19875ca6 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 1bc3a716..4575e155 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 1bc3a716..134fda4a 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 56eb9565..b6c83a08 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 8dccf530..76d6a784 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 56a18c07..ec58fb24 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 afe89a48..7d7d94c5 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 34e4571c..0fd819e1 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 34e4571c..ae0715ce 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 dac9ec50..d770d4c3 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 09e8f553..296e6dec 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 063e3ab0..0a7ffd2e 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 063e3ab0..20e97e3b 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 c6165e55..3660491c 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 c6165e55..ad108a7d 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 635767a1..2fe6dd6c 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 635767a1..97963e23 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 53572eaa..811cbd9b 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 53572eaa..494eadf0 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 09a31fc7..f7060746 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 09a31fc7..10ee9fea 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 2377f028..42b75ad3 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 2377f028..f953b885 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 83e5bfea..d34f15bc 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 83e5bfea..bc1a724b 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 0bdef036..188066e5 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 0bdef036..04ed43a5 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 00000000..71b54cd5 --- /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 00000000..d6135885 --- /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 00000000..08158aa7 --- /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 00000000..6e02c00b --- /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 00000000..6e02c00b --- /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 fa63d7d0..c9397c7a 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 fa63d7d0..67951205 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); + }); + } +}