diff --git a/Dapper/NRT.cs b/Dapper/NRT.cs new file mode 100644 index 000000000..47c4366e6 --- /dev/null +++ b/Dapper/NRT.cs @@ -0,0 +1,12 @@ +#if !NET5_0_OR_GREATER +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + public bool ReturnValue { get; } + } +} +#endif diff --git a/Dapper/SqlMapper.DapperRow.cs b/Dapper/SqlMapper.DapperRow.cs index 309222459..82b88d221 100644 --- a/Dapper/SqlMapper.DapperRow.cs +++ b/Dapper/SqlMapper.DapperRow.cs @@ -46,14 +46,14 @@ internal bool TryGetValue(int index, out object? value) { if (index < 0) { // doesn't exist - value = null!; + value = null; return false; } // exists, **even if** we don't have a value; consider table rows heterogeneous value = index < values.Length ? values[index] : null; if (value is DeadValue) { // pretend it isn't here - value = null!; + value = null; return false; } return true; diff --git a/Dapper/SqlMapper.Link.cs b/Dapper/SqlMapper.Link.cs index eb2c1bcde..92b434881 100644 --- a/Dapper/SqlMapper.Link.cs +++ b/Dapper/SqlMapper.Link.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System.Diagnostics.CodeAnalysis; +using System.Threading; namespace Dapper { @@ -14,18 +15,18 @@ public static partial class SqlMapper internal class Link where TKey : class { public static void Clear(ref Link? head) => Interlocked.Exchange(ref head, null); - public static bool TryGet(Link? link, TKey key, out TValue value) + public static bool TryGet(Link? link, TKey key, [NotNullWhen(true)] out TValue? value) { while (link is not null) { if ((object)key == (object)link.Key) { - value = link.Value; + value = link.Value!; return true; } link = link.Tail; } - value = default!; + value = default; return false; } @@ -35,7 +36,7 @@ public static bool TryAdd(ref Link? head, TKey key, ref TValue val do { var snapshot = Interlocked.CompareExchange(ref head, null, null); - if (TryGet(snapshot, key, out TValue found)) + if (TryGet(snapshot, key, out TValue? found)) { // existing match; report the existing value instead value = found; return false; diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index 13ce5564e..56f9d4eda 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -89,14 +89,15 @@ private static void CollectCacheGarbage() private const int COLLECT_PER_ITEMS = 1000, COLLECT_HIT_COUNT_MIN = 0; private static int collect; - private static bool TryGetQueryCache(Identity key, out CacheInfo value) + + private static bool TryGetQueryCache(Identity key, [NotNullWhen(true)] out CacheInfo? value) { if (_queryCache.TryGetValue(key, out value!)) { value.RecordHit(); return true; } - value = null!; + value = null; return false; } @@ -1817,7 +1818,7 @@ private static int GetNextSplit(int startIdx, string splitOn, DbDataReader reade private static CacheInfo GetCacheInfo(Identity identity, object? exampleParameters, bool addToCache) { - if (!TryGetQueryCache(identity, out CacheInfo info)) + if (!TryGetQueryCache(identity, out CacheInfo? info)) { if (GetMultiExec(exampleParameters) is not null) {