From 0c4d20e5dd918407fb90af36d6862ebbef43bde1 Mon Sep 17 00:00:00 2001 From: SENESO Date: Thu, 8 Oct 2026 19:43:34 +0300 Subject: [PATCH] Fix PostgreSQL array to interface mapping regression (fixes #2231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DateOnly/TimeOnly re-enable (6d48ef6) added a TypeCode.Object guard that blocks legitimate direct unboxes where both sides report Object but the runtime type satisfies the target — e.g. short[] to IReadOnlyList. Adds unboxType.IsAssignableFrom(colType) as a direct-unbox trigger. IReadOnlyList.IsAssignableFrom(short[]) is true (fix works), while TimeOnly.IsAssignableFrom(TimeSpan) is false (the original DateOnly/TimeOnly fix stays intact). --- Dapper/SqlMapper.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index 8f3956cab..1e62c679c 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -3855,9 +3855,12 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind // matching TypeCode.Object says nothing (TimeSpan vs TimeOnly?, say), and a direct // unbox there throws; such pairs belong to the flexible-convert path below. A column // reported as plain *object* (sql_variant etc) keeps the direct unbox: the runtime - // box is the only truth available there + // box is the only truth available there; an interface/base type implemented + // by the column type (e.g. short[] -> IReadOnlyList) is also + // safe to unbox directly (see #2231) if ((hasTypeHandler = typeHandlers.ContainsKey(unboxType)) || colType == unboxType || colType == typeof(object) || unboxType == typeof(object) + || unboxType.IsAssignableFrom(colType) || (dataTypeCode == unboxTypeCode && dataTypeCode != TypeCode.Object) || (dataTypeCode == Type.GetTypeCode(nullUnderlyingType) && dataTypeCode != TypeCode.Object) || colType == nullUnderlyingType)