From 0600f91f56bcd37786e98afc5a0c697ee5292ae2 Mon Sep 17 00:00:00 2001 From: tr00d Date: Fri, 31 Jul 2026 11:11:16 +0200 Subject: [PATCH 1/8] chore: remove unused using directives --- Core/Attributes/MapToAttribute.cs | 4 +--- Core/Diagnostics/Instrumentation.cs | 1 - Core/Extensions/DictionaryExtensions.cs | 4 +--- Core/Helpers.cs | 2 -- Core/Interfaces/IGettableHeaders.cs | 1 - 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Core/Attributes/MapToAttribute.cs b/Core/Attributes/MapToAttribute.cs index 3877043..d3ac0d6 100644 --- a/Core/Attributes/MapToAttribute.cs +++ b/Core/Attributes/MapToAttribute.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace Supabase.Core.Attributes { @@ -14,7 +12,7 @@ public class MapToAttribute : Attribute /// The externally specified target value. /// public string Mapping { get; set; } - + /// /// A formatter to be passed into the method. /// diff --git a/Core/Diagnostics/Instrumentation.cs b/Core/Diagnostics/Instrumentation.cs index ec81799..deb918d 100644 --- a/Core/Diagnostics/Instrumentation.cs +++ b/Core/Diagnostics/Instrumentation.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics; using System.Diagnostics.Metrics; using System.Reflection; diff --git a/Core/Extensions/DictionaryExtensions.cs b/Core/Extensions/DictionaryExtensions.cs index c3bf09e..ecc5536 100644 --- a/Core/Extensions/DictionaryExtensions.cs +++ b/Core/Extensions/DictionaryExtensions.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; namespace Supabase.Core.Extensions { diff --git a/Core/Helpers.cs b/Core/Helpers.cs index 54ba0f2..199f06f 100644 --- a/Core/Helpers.cs +++ b/Core/Helpers.cs @@ -1,8 +1,6 @@ using Supabase.Core.Attributes; using System; -using System.Collections.Generic; using System.Linq; -using System.Text; namespace Supabase.Core { diff --git a/Core/Interfaces/IGettableHeaders.cs b/Core/Interfaces/IGettableHeaders.cs index 4c913c6..b601e09 100644 --- a/Core/Interfaces/IGettableHeaders.cs +++ b/Core/Interfaces/IGettableHeaders.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; namespace Supabase.Core.Interfaces { From 5187bc0ee5be2f42594cb87f4bef0ae2346d3bac Mon Sep 17 00:00:00 2001 From: tr00d Date: Fri, 31 Jul 2026 11:11:44 +0200 Subject: [PATCH 2/8] chore: add this identifier on properties --- Core/Attributes/MapToAttribute.cs | 4 +-- Core/Util.cs | 8 +++--- .../Diagnostics/ActivityExtensionsTests.cs | 26 +++++++++---------- .../UnityApiCompatibilityVersionAttribute.cs | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Core/Attributes/MapToAttribute.cs b/Core/Attributes/MapToAttribute.cs index d3ac0d6..3a6cbec 100644 --- a/Core/Attributes/MapToAttribute.cs +++ b/Core/Attributes/MapToAttribute.cs @@ -27,8 +27,8 @@ public class MapToAttribute : Attribute /// public MapToAttribute(string mapping, string? formatter = null) { - Mapping = mapping; - Formatter = formatter; + this.Mapping = mapping; + this.Formatter = formatter; } } } diff --git a/Core/Util.cs b/Core/Util.cs index 3ad8f02..7002d9e 100644 --- a/Core/Util.cs +++ b/Core/Util.cs @@ -51,10 +51,10 @@ internal MetadataEntry(string key, string value, string? version = null) this.version = version; } - public override string ToString() => string.IsNullOrEmpty(version) - ? $"; {key}={value}" - : $"; {key}={value}; {key}-version={version}"; - + public override string ToString() => string.IsNullOrEmpty(this.version) + ? $"; {this.key}={this.value}" + : $"; {this.key}={this.value}; {this.key}-version={this.version}"; + internal static MetadataEntry Unknown(string key) => new MetadataEntry(key, "unknown"); } diff --git a/CoreTests/Diagnostics/ActivityExtensionsTests.cs b/CoreTests/Diagnostics/ActivityExtensionsTests.cs index 4541003..d1c4806 100644 --- a/CoreTests/Diagnostics/ActivityExtensionsTests.cs +++ b/CoreTests/Diagnostics/ActivityExtensionsTests.cs @@ -22,27 +22,27 @@ public class ActivityExtensionsTests public ActivityExtensionsTests() { - listener = new ActivityListener + this.listener = new ActivityListener { - ShouldListenTo = candidate => candidate == source, + ShouldListenTo = candidate => candidate == this.source, Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllDataAndRecorded }; - ActivitySource.AddActivityListener(listener); + ActivitySource.AddActivityListener(this.listener); } [TestCleanup] public void Cleanup() { - listener.Dispose(); - source.Dispose(); + this.listener.Dispose(); + this.source.Dispose(); } - private Activity StartActivity() => source.StartActivity("operation")!; + private Activity StartActivity() => this.source.StartActivity("operation")!; [TestMethod] public void SetHttpRequestTags_ShouldTagMethodHostAndSanitizedUrl() { - using var activity = StartActivity(); + using var activity = this.StartActivity(); activity.SetHttpRequestTags("POST", new Uri("https://project.supabase.co/auth/v1/token?apikey=secret")); using (new AssertionScope()) { @@ -56,7 +56,7 @@ public void SetHttpRequestTags_ShouldTagMethodHostAndSanitizedUrl() [TestMethod] public void SetHttpRequestTags_ShouldTagPort_GivenNonDefaultPort() { - using var activity = StartActivity(); + using var activity = this.StartActivity(); activity.SetHttpRequestTags("GET", new Uri("http://127.0.0.1:54321/auth/v1/token")); activity.GetTagItem("server.port").Should().Be(54321); } @@ -64,7 +64,7 @@ public void SetHttpRequestTags_ShouldTagPort_GivenNonDefaultPort() [TestMethod] public void SetHttpRequestTags_ShouldNotTagPort_GivenDefaultPort() { - using var activity = StartActivity(); + using var activity = this.StartActivity(); activity.SetHttpRequestTags("GET", new Uri("https://project.supabase.co/auth/v1/token")); activity.GetTagItem("server.port").Should().BeNull(); } @@ -76,7 +76,7 @@ public void SetHttpRequestTags_ShouldReturnNull_GivenNullActivity() => [TestMethod] public void SetHttpResponseTags_ShouldTagStatusCode() { - using var activity = StartActivity(); + using var activity = this.StartActivity(); activity.SetHttpResponseTags(200); using (new AssertionScope()) { @@ -88,7 +88,7 @@ public void SetHttpResponseTags_ShouldTagStatusCode() [TestMethod] public void SetHttpResponseTags_ShouldMarkError_GivenStatusAtErrorBoundary() { - using var activity = StartActivity(); + using var activity = this.StartActivity(); activity.SetHttpResponseTags(400); using (new AssertionScope()) { @@ -100,7 +100,7 @@ public void SetHttpResponseTags_ShouldMarkError_GivenStatusAtErrorBoundary() [TestMethod] public void SetHttpResponseTags_ShouldNotMarkError_GivenLastSuccessStatus() { - using var activity = StartActivity(); + using var activity = this.StartActivity(); activity.SetHttpResponseTags(399); using (new AssertionScope()) { @@ -116,7 +116,7 @@ public void SetHttpResponseTags_ShouldReturnNull_GivenNullActivity() => [TestMethod] public void SetFailure_ShouldTagExceptionTypeAndErrorStatus() { - using var activity = StartActivity(); + using var activity = this.StartActivity(); activity.SetFailure(new InvalidOperationException("boom")); using (new AssertionScope()) { diff --git a/CoreTests/TestDoubles/UnityApiCompatibilityVersionAttribute.cs b/CoreTests/TestDoubles/UnityApiCompatibilityVersionAttribute.cs index 3eccdee..d98e676 100644 --- a/CoreTests/TestDoubles/UnityApiCompatibilityVersionAttribute.cs +++ b/CoreTests/TestDoubles/UnityApiCompatibilityVersionAttribute.cs @@ -12,7 +12,7 @@ namespace CoreTests.TestDoubles; [AttributeUsage(AttributeTargets.Assembly)] internal sealed class UnityAPICompatibilityVersionAttribute : Attribute { - public UnityAPICompatibilityVersionAttribute(string version) => Version = version; + public UnityAPICompatibilityVersionAttribute(string version) => this.Version = version; public string Version { get; } } From f47dbeff24955f41c6854d55e267c368bf9df682 Mon Sep 17 00:00:00 2001 From: tr00d Date: Fri, 31 Jul 2026 11:17:01 +0200 Subject: [PATCH 3/8] refactor: move ActivityExtensions on the new extensions pattern --- Core/Diagnostics/ActivityExtensions.cs | 93 ++++++++++++++------------ 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/Core/Diagnostics/ActivityExtensions.cs b/Core/Diagnostics/ActivityExtensions.cs index 93bfebc..e8f9ec6 100644 --- a/Core/Diagnostics/ActivityExtensions.cs +++ b/Core/Diagnostics/ActivityExtensions.cs @@ -14,60 +14,67 @@ namespace Supabase.Core.Diagnostics /// public static class ActivityExtensions { - /// - /// Tags an outgoing HTTP request following OpenTelemetry HTTP client conventions. - /// The URL is sanitized to scheme/host/port/path; the query string is never recorded. - /// /// The activity to tag, or null when nothing is listening. - /// The HTTP method, e.g. POST. - /// The request URI, sanitized before tagging. - public static Activity? SetHttpRequestTags(this Activity? activity, string method, Uri uri) + extension(Activity? activity) { - if (activity == null) - return null; + /// + /// Tags an outgoing HTTP request following OpenTelemetry HTTP client conventions. + /// The URL is sanitized to scheme/host/port/path; the query string is never recorded. + /// + /// The HTTP method, e.g. POST. + /// The request URI, sanitized before tagging. + public Activity? SetHttpRequestTags(string method, Uri uri) + { + if (activity == null) + return null; - activity.SetTag("http.request.method", method); - activity.SetTag("server.address", uri.Host); - if (!uri.IsDefaultPort) - activity.SetTag("server.port", uri.Port); + activity.SetTag("http.request.method", method); + activity.SetTag("server.address", uri.Host); + if (!uri.IsDefaultPort) + activity.SetTag("server.port", uri.Port); - activity.SetTag("url.full", UrlSanitizer.Sanitize(uri)); - return activity; - } + activity.SetTag("url.full", UrlSanitizer.Sanitize(uri)); + return activity; + } - /// - /// Tags the response status code, marking the activity as failed for 4xx/5xx responses. - /// - /// The activity to tag, or null when nothing is listening. - /// The HTTP response status code. - public static Activity? SetHttpResponseTags(this Activity? activity, int statusCode) - { - if (activity == null) - return null; + /// + /// Tags the response status code, marking the activity as failed for 4xx/5xx responses. + /// + /// The HTTP response status code. + public Activity? SetHttpResponseTags(int statusCode) + { + if (activity == null) + return null; + + activity.SetTag("http.response.status_code", statusCode); + return statusCode >= 400 ? activity.SetErrorTags( statusCode) : activity; + } - activity.SetTag("http.response.status_code", statusCode); - if (statusCode >= 400) + /// + /// Marks the activity as failed with the exception type as error.type. + /// + /// The exception whose type and message describe the failure. + public Activity? SetFailure(Exception exception) { - activity.SetTag("error.type", statusCode.ToString()); - activity.SetStatus(ActivityStatusCode.Error); + if (activity == null) + return null; + + activity.SetTag("error.type", exception.GetType().FullName); + activity.SetStatus(ActivityStatusCode.Error, exception.Message); + return activity; } - return activity; - } - /// - /// Marks the activity as failed with the exception type as error.type. - /// - /// The activity to tag, or null when nothing is listening. - /// The exception whose type and message describe the failure. - public static Activity? SetFailure(this Activity? activity, Exception exception) - { - if (activity == null) - return null; + private Activity? SetErrorTags( int statusCode) + { + if (activity == null) + return null; - activity.SetTag("error.type", exception.GetType().FullName); - activity.SetStatus(ActivityStatusCode.Error, exception.Message); - return activity; + activity.SetTag("error.type", statusCode.ToString()); + activity.SetStatus(ActivityStatusCode.Error); + return activity; + } } + } } From 8f24e5634803ee0fbba81df51be3eeb4f4129109 Mon Sep 17 00:00:00 2001 From: tr00d Date: Fri, 31 Jul 2026 11:17:35 +0200 Subject: [PATCH 4/8] chore: use target-type new --- Core/Diagnostics/Instrumentation.cs | 6 ++---- Core/Util.cs | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Core/Diagnostics/Instrumentation.cs b/Core/Diagnostics/Instrumentation.cs index deb918d..d2d8efb 100644 --- a/Core/Diagnostics/Instrumentation.cs +++ b/Core/Diagnostics/Instrumentation.cs @@ -20,8 +20,7 @@ public static class Instrumentation /// /// The assembly whose version identifies the emitting library. /// The source name, e.g. Supabase.Gotrue. - public static ActivitySource CreateActivitySource(Assembly assembly, string name) => - new ActivitySource(name, GetVersion(assembly)); + public static ActivitySource CreateActivitySource(Assembly assembly, string name) => new(name, GetVersion(assembly)); /// /// Creates the for a Supabase client library, versioned from the @@ -29,8 +28,7 @@ public static ActivitySource CreateActivitySource(Assembly assembly, string name /// /// The assembly whose version identifies the emitting library. /// The meter name, e.g. Supabase.Gotrue. - public static Meter CreateMeter(Assembly assembly, string name) => - new Meter(name, GetVersion(assembly)); + public static Meter CreateMeter(Assembly assembly, string name) => new(name, GetVersion(assembly)); /// /// Resolves the version of an assembly, preferring the informational (package) version diff --git a/Core/Util.cs b/Core/Util.cs index 7002d9e..e9292d3 100644 --- a/Core/Util.cs +++ b/Core/Util.cs @@ -55,7 +55,7 @@ public override string ToString() => string.IsNullOrEmpty(this.version) ? $"; {this.key}={this.value}" : $"; {this.key}={this.value}; {this.key}-version={this.version}"; - internal static MetadataEntry Unknown(string key) => new MetadataEntry(key, "unknown"); + internal static MetadataEntry Unknown(string key) => new(key, "unknown"); } private static string GetPlatform(string osDescription, Func isOsPlatform) @@ -69,9 +69,9 @@ private static string GetPlatform(string osDescription, Func i return osDescription; } - private static MetadataEntry GetPlatformInfo(string osDescription, Func isOsPlatform) => new MetadataEntry("platform", GetPlatform(osDescription, isOsPlatform), Environment.OSVersion.Version.ToString()); + private static MetadataEntry GetPlatformInfo(string osDescription, Func isOsPlatform) => new("platform", GetPlatform(osDescription, isOsPlatform), Environment.OSVersion.Version.ToString()); - private static MetadataEntry GetRuntimeInfo() => new MetadataEntry("runtime", "dotnet", Environment.Version.ToString()); + private static MetadataEntry GetRuntimeInfo() => new("runtime", "dotnet", Environment.Version.ToString()); // Priority is explicit: MAUI wins over Blazor in hybrid apps where both assemblies are present. // Unity version uses GetCustomAttributesData() rather than member reflection — safe under IL2CPP. From fe7f92acb9c04b3ad54251f09638f781e5364d7e Mon Sep 17 00:00:00 2001 From: tr00d Date: Fri, 31 Jul 2026 11:17:53 +0200 Subject: [PATCH 5/8] chore: use collection expression --- Core/Diagnostics/UrlSanitizer.cs | 2 +- Core/Util.cs | 2 +- CoreTests/UtilTests.cs | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Core/Diagnostics/UrlSanitizer.cs b/Core/Diagnostics/UrlSanitizer.cs index 75ef9e8..83b58c6 100644 --- a/Core/Diagnostics/UrlSanitizer.cs +++ b/Core/Diagnostics/UrlSanitizer.cs @@ -42,7 +42,7 @@ public static string Sanitize(string url) => private static string StripAfterPath(string url) { - var delimiterIndex = url.IndexOfAny(new[] { '?', '#' }); + var delimiterIndex = url.IndexOfAny(['?', '#']); return delimiterIndex < 0 ? url : url.Substring(0, delimiterIndex); } } diff --git a/Core/Util.cs b/Core/Util.cs index e9292d3..5b1baf1 100644 --- a/Core/Util.cs +++ b/Core/Util.cs @@ -96,7 +96,7 @@ private static MetadataEntry GetFrameworkInfo(IReadOnlyCollection load private static CustomAttributeData[] SafeGetCustomAttributesData(Assembly assembly) { try { return assembly.GetCustomAttributesData().ToArray(); } - catch { return Array.Empty(); } + catch { return []; } } private static string? GetUnityVersion(IReadOnlyCollection loadedAssemblies) diff --git a/CoreTests/UtilTests.cs b/CoreTests/UtilTests.cs index b992f51..d59c32b 100644 --- a/CoreTests/UtilTests.cs +++ b/CoreTests/UtilTests.cs @@ -21,7 +21,7 @@ namespace CoreTests; public class UtilTests { private static readonly Func NoPlatform = _ => false; - private static readonly IReadOnlyCollection NoFrameworks = Array.Empty(); + private static readonly IReadOnlyCollection NoFrameworks = []; [TestMethod] public void GetAssemblyVersion_ShouldStartWithClientNameAndVersion() => @@ -84,25 +84,25 @@ public void GetAssemblyVersion_ShouldReportUnknownFramework_GivenNoKnownFramewor [TestMethod] public void GetAssemblyVersion_ShouldReportMauiFramework_GivenMauiAssembly() => - HeaderWith(new[] { FakeAssembly.Named("Microsoft.Maui") }).Should().Contain("; framework=maui"); + HeaderWith([FakeAssembly.Named("Microsoft.Maui")]).Should().Contain("; framework=maui"); [TestMethod] public void GetAssemblyVersion_ShouldReportBlazorFramework_GivenBlazorAssembly() => - HeaderWith(new[] { FakeAssembly.Named("Microsoft.AspNetCore.Components") }).Should().Contain("; framework=blazor"); + HeaderWith([FakeAssembly.Named("Microsoft.AspNetCore.Components")]).Should().Contain("; framework=blazor"); [TestMethod] public void GetAssemblyVersion_ShouldPreferMauiOverBlazor_GivenBothAssemblies() => - HeaderWith(new[] { FakeAssembly.Named("Microsoft.AspNetCore.Components"), FakeAssembly.Named("Microsoft.Maui") }) + HeaderWith([FakeAssembly.Named("Microsoft.AspNetCore.Components"), FakeAssembly.Named("Microsoft.Maui")]) .Should().Contain("; framework=maui", "MAUI wins over Blazor in hybrid apps where both are present"); [TestMethod] public void GetAssemblyVersion_ShouldReportUnityFrameworkWithVersion_GivenUnityAssembly() => - HeaderWith(new[] { FakeAssembly.Named("UnityEngine.CoreModule"), typeof(UtilTests).Assembly }) + HeaderWith([FakeAssembly.Named("UnityEngine.CoreModule"), typeof(UtilTests).Assembly]) .Should().Contain("; framework=unity; framework-version=2022.3.5f1"); [TestMethod] public void GetAssemblyVersion_ShouldReportUnityFrameworkWithoutVersion_GivenNoUnityVersionAttribute() => - HeaderWith(new[] { FakeAssembly.Named("UnityEngine.CoreModule") }) + HeaderWith([FakeAssembly.Named("UnityEngine.CoreModule")]) .Should().Contain("; framework=unity").And.NotContain("framework-version", "an absent Unity version attribute must resolve to no version, not throw"); From 7e87034d2e8f71b25db4dae57327afd6d0d20aa6 Mon Sep 17 00:00:00 2001 From: tr00d Date: Fri, 31 Jul 2026 11:18:14 +0200 Subject: [PATCH 6/8] chore: use var when possible --- Core/Extensions/DictionaryExtensions.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/Extensions/DictionaryExtensions.cs b/Core/Extensions/DictionaryExtensions.cs index ecc5536..aaa0a53 100644 --- a/Core/Extensions/DictionaryExtensions.cs +++ b/Core/Extensions/DictionaryExtensions.cs @@ -10,11 +10,11 @@ public static class DictionaryExtensions { /// /// Merges two dictionaries, allowing overwrite priorities leftward. - /// + /// /// Works in C#3/VS2008: /// Returns a new dictionary of this ... others merged leftward. /// Keeps the type of 'this', which must be default-instantiable. - /// Example: + /// Example: /// result = map.MergeLeft(other1, other2, ...) /// From: https://stackoverflow.com/a/2679857/3629438 /// @@ -27,10 +27,10 @@ public static class DictionaryExtensions public static T MergeLeft(this T me, params IDictionary[] others) where T : IDictionary, new() { - T newMap = new T(); - foreach (IDictionary src in (new List> { me }).Concat(others)) + var newMap = new T(); + foreach (var src in (new List> { me }).Concat(others)) { - foreach (KeyValuePair p in src) + foreach (var p in src) { newMap[p.Key] = p.Value; } From e23ad65f04fe0b60f233e232f3abe8f9fd227ac8 Mon Sep 17 00:00:00 2001 From: tr00d Date: Fri, 31 Jul 2026 11:36:36 +0200 Subject: [PATCH 7/8] chore: fix XML comments --- Core/Helpers.cs | 5 ++--- Core/Util.cs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Core/Helpers.cs b/Core/Helpers.cs index 199f06f..d4acee2 100644 --- a/Core/Helpers.cs +++ b/Core/Helpers.cs @@ -17,7 +17,7 @@ public static class Helpers /// /// public static T GetPropertyValue(object obj, string propName) => (T)obj.GetType().GetProperty(propName).GetValue(obj, null); - + /// /// Returns a cast Custom Attribute from a given object. /// @@ -25,7 +25,7 @@ public static class Helpers /// /// public static T GetCustomAttribute(object obj) where T : Attribute => (T)Attribute.GetCustomAttribute(obj.GetType(), typeof(T)); - + /// /// Returns a cast Custom Attribute from a given type. /// @@ -43,7 +43,6 @@ public static MapToAttribute GetMappedToAttr(Enum obj) { var type = obj.GetType(); var name = Enum.GetName(type, obj); - return type.GetField(name).GetCustomAttributes(false).OfType().SingleOrDefault(); } } diff --git a/Core/Util.cs b/Core/Util.cs index 5b1baf1..0ba9e0c 100644 --- a/Core/Util.cs +++ b/Core/Util.cs @@ -26,7 +26,7 @@ public static string GetAssemblyVersion(Type clientType) => // Testability seam: the platform and framework probes read process-wide ambient state // (RuntimeInformation, the loaded assembly set) that a host cannot vary at runtime. This - // overload takes those reads as parameters so every branch is reachable hermetically; the + // overload takes those reads as parameters, so every branch is reachable hermetically; the // public entry point above supplies the real values. Internal — not part of the public API. internal static string GetAssemblyVersion(Type clientType, string osDescription, Func isOsPlatform, IReadOnlyCollection loadedAssemblies) => $"{GetClientName(clientType)}-csharp/{GetClientVersion(clientType)}{BuildMetadata(osDescription, isOsPlatform, loadedAssemblies)}"; From c1c90dee0b2d052296950e9317ba08ee6c1e96d4 Mon Sep 17 00:00:00 2001 From: tr00d Date: Fri, 31 Jul 2026 11:44:23 +0200 Subject: [PATCH 8/8] refactor: simplify MergeLeft --- Core/Extensions/DictionaryExtensions.cs | 22 +++++++------------ .../Extensions/DictionaryExtensionsTests.cs | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Core/Extensions/DictionaryExtensions.cs b/Core/Extensions/DictionaryExtensions.cs index aaa0a53..a9a07ff 100644 --- a/Core/Extensions/DictionaryExtensions.cs +++ b/Core/Extensions/DictionaryExtensions.cs @@ -21,21 +21,15 @@ public static class DictionaryExtensions /// /// /// - /// - /// + /// + /// /// - public static T MergeLeft(this T me, params IDictionary[] others) - where T : IDictionary, new() - { - var newMap = new T(); - foreach (var src in (new List> { me }).Concat(others)) + public static T MergeLeft(this T me, params IDictionary[] others) + where T : IDictionary, new() => + others.Prepend(me).SelectMany(pairs => pairs).Aggregate(new T(), (newMap, pair) => { - foreach (var p in src) - { - newMap[p.Key] = p.Value; - } - } - return newMap; - } + newMap[pair.Key] = pair.Value; + return newMap; + }); } } diff --git a/CoreTests/Extensions/DictionaryExtensionsTests.cs b/CoreTests/Extensions/DictionaryExtensionsTests.cs index 36537ea..85efd24 100644 --- a/CoreTests/Extensions/DictionaryExtensionsTests.cs +++ b/CoreTests/Extensions/DictionaryExtensionsTests.cs @@ -6,7 +6,7 @@ namespace CoreTests.Extensions; /// -/// Covers : a new dictionary combining every +/// Covers : a new dictionary combining every /// source, with later sources overwriting earlier keys, leaving the originals untouched. /// [TestClass]