From a5b5bbcb65facd09b2dd5f3c6087598ac63ea1d2 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 02:49:01 +0200 Subject: [PATCH 01/19] move all pollyfills to a common folder --- .../Common/src/Polyfills/ArrayPolyfills.cs | 14 +++++ .../Common/src/Polyfills/BitArrayPolyfills.cs | 27 ++++++++++ .../src/Polyfills/CollectionsPolyfills.cs | 18 +++++++ .../src/Polyfills/DateTimeOffsetPolyfills.cs | 15 ++++++ .../src/Polyfills/DictionaryPolyfills.cs | 54 +++++++++++++++++++ .../Common/src/Polyfills/DoublePolyfills.cs | 15 ++++++ .../src/Polyfills/EnvironmentPolyfills.cs | 16 ++++++ .../Common/src/Polyfills/HashCodePolyfills.cs | 25 +++++++++ .../src/Polyfills/OperatingSystemPolyfills.cs | 19 +++++++ .../Common/src/Polyfills/SinglePolyfills.cs | 15 ++++++ .../src/Polyfills/StopwatchPolyfills.cs | 22 ++++++++ .../Common/src/Polyfills/StreamPolyfills.cs | 33 ++++++++++++ .../src/Polyfills/TextWriterPolyfills.cs | 15 ++++++ ...t.Extensions.FileProviders.Physical.csproj | 4 ++ .../src/PhysicalFileProvider.cs | 2 - .../src/PhysicalFilesWatcher.cs | 2 - ...icrosoft.Extensions.Hosting.Systemd.csproj | 1 + .../src/SystemdHelpers.cs | 4 -- .../src/AnsiParsingLogConsole.cs | 4 -- .../src/JsonConsoleFormatter.cs | 17 ------ ...icrosoft.Extensions.Logging.Console.csproj | 3 ++ .../src/SimpleConsoleFormatter.cs | 4 -- .../src/System.Collections.Immutable.csproj | 2 + .../Collections/Frozen/FrozenHashTable.cs | 4 -- .../src/System/Polyfills.cs | 13 ----- ...System.Diagnostics.DiagnosticSource.csproj | 1 + .../Base2ExponentialHistogramAggregator.cs | 10 +--- .../src/System.Formats.Cbor.csproj | 2 + .../Formats/Cbor/CborConformanceLevel.cs | 13 ----- .../Formats/Cbor/Writer/CborWriter.Tag.cs | 4 -- .../src/System.IO.Hashing.csproj | 1 + .../Hashing/NonCryptographicHashAlgorithm.cs | 3 -- .../src/Internal/Synthesis/AudioBase.cs | 13 ----- .../src/Internal/Synthesis/EngineSite.cs | 13 ----- .../System.Speech/src/System.Speech.csproj | 1 + .../src/System.Text.Json.csproj | 3 ++ .../src/System/Text/Json/JsonHelpers.cs | 35 ++---------- .../src/System.Threading.RateLimiting.csproj | 1 + .../RateLimiting/RateLimiterHelper.cs | 11 ---- 39 files changed, 313 insertions(+), 146 deletions(-) create mode 100644 src/libraries/Common/src/Polyfills/ArrayPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/DoublePolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/HashCodePolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/SinglePolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/StreamPolyfills.cs create mode 100644 src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs diff --git a/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs b/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs new file mode 100644 index 00000000000000..53fe041627093b --- /dev/null +++ b/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System +{ + /// Provides downlevel polyfills for static members on . + internal static class ArrayPolyfills + { + extension(Array) + { + public static int MaxLength => 0x7FFFFFC7; + } + } +} diff --git a/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs b/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs new file mode 100644 index 00000000000000..5d84c4e938e437 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; + +namespace System.Collections +{ + /// Provides downlevel polyfills for instance methods on . + internal static class BitArrayPolyfills + { + extension(BitArray bitArray) + { + public bool HasAllSet() + { + for (int i = 0; i < bitArray.Count; i++) + { + if (!bitArray[i]) + { + return false; + } + } + + return true; + } + } + } +} diff --git a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs new file mode 100644 index 00000000000000..58d03c31250e61 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel; + +namespace System.Collections.Generic +{ + /// Provides downlevel polyfills for . + internal static class KeyValuePairPolyfills + { + [EditorBrowsable(EditorBrowsableState.Never)] + public static void Deconstruct(this KeyValuePair source, out TKey key, out TValue value) + { + key = source.Key; + value = source.Value; + } + } +} diff --git a/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs b/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs new file mode 100644 index 00000000000000..335cfa6f94b016 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System +{ + /// Provides downlevel polyfills for instance members on . + internal static class DateTimeOffsetPolyfills + { + extension(DateTimeOffset value) + { + public int TotalOffsetMinutes => + (int)(value.Offset.Ticks / TimeSpan.TicksPerMinute); + } + } +} diff --git a/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs new file mode 100644 index 00000000000000..ae512bac84f2b4 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; + +namespace System.Collections.Generic +{ + /// Provides downlevel polyfills for instance methods on dictionary types. + internal static class DictionaryPolyfills + { + extension(Dictionary dictionary) where TKey : notnull + { + public bool TryAdd(TKey key, TValue value) + { + if (!dictionary.ContainsKey(key)) + { + dictionary[key] = value; + return true; + } + + return false; + } + } + + extension(IDictionary dictionary) where TKey : notnull + { + public bool TryAdd(TKey key, TValue value) + { + if (!dictionary.ContainsKey(key)) + { + dictionary[key] = value; + return true; + } + + return false; + } + } + + extension(Queue queue) + { + public bool TryDequeue([NotNullWhen(true)] out T? result) + { + if (queue.Count > 0) + { + result = queue.Dequeue(); + return true; + } + + result = default; + return false; + } + } + } +} diff --git a/src/libraries/Common/src/Polyfills/DoublePolyfills.cs b/src/libraries/Common/src/Polyfills/DoublePolyfills.cs new file mode 100644 index 00000000000000..51608461f2fcb7 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/DoublePolyfills.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System +{ + /// Provides downlevel polyfills for static methods on . + internal static class DoublePolyfills + { + extension(double) + { + public static bool IsFinite(double value) => + !(double.IsNaN(value) || double.IsInfinity(value)); + } + } +} diff --git a/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs b/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs new file mode 100644 index 00000000000000..e168c3720a27d2 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System +{ + /// Provides downlevel polyfills for static members on . + internal static class EnvironmentPolyfills + { + extension(Environment) + { + public static int ProcessId => Process.GetCurrentProcess().Id; + } + } +} diff --git a/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs b/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs new file mode 100644 index 00000000000000..ff2f0d2beed601 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +namespace System +{ + /// Provides downlevel polyfills for instance methods on . + internal static class HashCodePolyfills + { + public static void AddBytes(this ref HashCode hashCode, ReadOnlySpan value) + { + while (value.Length >= sizeof(int)) + { + hashCode.Add(MemoryMarshal.Read(value)); + value = value.Slice(sizeof(int)); + } + + foreach (byte b in value) + { + hashCode.Add(b); + } + } + } +} diff --git a/src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs b/src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs new file mode 100644 index 00000000000000..3df265fb3df034 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System +{ + /// Provides downlevel polyfills for static methods on . + internal static class OperatingSystemPolyfills + { + extension(OperatingSystem) + { + public static bool IsAndroid() => false; + public static bool IsBrowser() => false; + public static bool IsIOS() => false; + public static bool IsMacCatalyst() => false; + public static bool IsTvOS() => false; + public static bool IsWasi() => false; + } + } +} diff --git a/src/libraries/Common/src/Polyfills/SinglePolyfills.cs b/src/libraries/Common/src/Polyfills/SinglePolyfills.cs new file mode 100644 index 00000000000000..f4dc02e7f65402 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/SinglePolyfills.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System +{ + /// Provides downlevel polyfills for static methods on . + internal static class SinglePolyfills + { + extension(float) + { + public static bool IsFinite(float value) => + !(float.IsNaN(value) || float.IsInfinity(value)); + } + } +} diff --git a/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs b/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs new file mode 100644 index 00000000000000..a70cdc2767e931 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Diagnostics +{ + /// Provides downlevel polyfills for static methods on . + internal static class StopwatchPolyfills + { + private static readonly double s_tickFrequency = (double)TimeSpan.TicksPerSecond / Stopwatch.Frequency; + + extension(Stopwatch) + { + public static TimeSpan GetElapsedTime(long startingTimestamp) => + new((long)((Stopwatch.GetTimestamp() - startingTimestamp) * s_tickFrequency)); + + public static TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp) => + new((long)((endingTimestamp - startingTimestamp) * s_tickFrequency)); + } + } +} diff --git a/src/libraries/Common/src/Polyfills/StreamPolyfills.cs b/src/libraries/Common/src/Polyfills/StreamPolyfills.cs new file mode 100644 index 00000000000000..798633266c73a0 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/StreamPolyfills.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading; +using System.Threading.Tasks; + +namespace System.IO +{ + /// Provides downlevel polyfills for instance methods on . + internal static class StreamPolyfills + { + extension(Stream stream) + { + public void ReadExactly(byte[] buffer) + { + int totalRead = 0; + while (totalRead < buffer.Length) + { + int read = stream.Read(buffer, totalRead, buffer.Length - totalRead); + if (read == 0) + { + throw new EndOfStreamException(); + } + + totalRead += read; + } + } + + public Task CopyToAsync(Stream destination, CancellationToken cancellationToken) => + stream.CopyToAsync(destination, 81_920, cancellationToken); + } + } +} diff --git a/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs b/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs new file mode 100644 index 00000000000000..fe26446fe4c128 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.IO +{ + /// Provides downlevel polyfills for instance methods on . + internal static class TextWriterPolyfills + { + extension(TextWriter writer) + { + public void Write(ReadOnlySpan value) => + writer.Write(value.ToString()); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj index ae7ebacc83bb92..83a966b155974d 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj @@ -20,6 +20,10 @@ Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" /> + + + + diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs index ede1b40f391a23..c7d9d6dffe2dc0 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs @@ -162,7 +162,6 @@ internal PhysicalFilesWatcher CreateFileWatcher() string root = PathUtils.EnsureTrailingSlash(Path.GetFullPath(Root)); FileSystemWatcher? watcher; -#if NET // For browser/iOS/tvOS we will proactively fallback to polling since FileSystemWatcher is not supported. if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()) || OperatingSystem.IsTvOS()) { @@ -171,7 +170,6 @@ internal PhysicalFilesWatcher CreateFileWatcher() watcher = null; } else -#endif { // When UsePollingFileWatcher & UseActivePolling are set, we won't use a FileSystemWatcher. watcher = UsePollingFileWatcher && UseActivePolling ? null : new FileSystemWatcher(root); diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs index 64531c2eb7a0a8..8e28f381fd4e98 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs @@ -84,12 +84,10 @@ public PhysicalFilesWatcher( if (fileSystemWatcher != null) { -#if NET if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()) || OperatingSystem.IsTvOS()) { throw new PlatformNotSupportedException(SR.Format(SR.FileSystemWatcher_PlatformNotSupported, typeof(FileSystemWatcher))); } -#endif _fileWatcher = fileSystemWatcher; _fileWatcher.IncludeSubdirectories = true; diff --git a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/Microsoft.Extensions.Hosting.Systemd.csproj b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/Microsoft.Extensions.Hosting.Systemd.csproj index 526c3c164f5ad3..909843fc4872d0 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/Microsoft.Extensions.Hosting.Systemd.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/Microsoft.Extensions.Hosting.Systemd.csproj @@ -10,6 +10,7 @@ + diff --git a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs index 0094144b740400..84e5fffffb10a7 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs @@ -37,11 +37,7 @@ private static bool GetIsSystemdService() // To support containerized systemd services, check if we're the main process (PID 1) // and if there are systemd environment variables defined for notifying the service // manager, or passing listen handles. -#if NET int processId = Environment.ProcessId; -#else - int processId = Process.GetCurrentProcess().Id; -#endif if (processId == 1) { diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs index 563fcacac6dadf..8b2cfc76762870 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs @@ -62,11 +62,7 @@ private void WriteToConsole(string message, int startIndex, int length, ConsoleC { ReadOnlySpan span = message.AsSpan(startIndex, length); var colorChanged = SetColor(background, foreground); -#if NET _textWriter.Write(span); -#else - _textWriter.Write(span.ToString()); -#endif if (colorChanged) { ResetColor(); diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs index 5e4a43846e842a..ecee8974578483 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs @@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; -using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using Microsoft.Extensions.Logging.Abstractions; @@ -106,19 +105,7 @@ private void WriteInternal(IExternalScopeProvider? scopeProvider, TextWriter tex var logMessageBuffer = ArrayPool.Shared.Rent(Encoding.UTF8.GetMaxCharCount(messageBytes.Length)); try { - #if NET var charsWritten = Encoding.UTF8.GetChars(messageBytes, logMessageBuffer); - #else - int charsWritten; - unsafe - { - fixed (byte* messageBytesPtr = messageBytes) - fixed (char* logMessageBufferPtr = logMessageBuffer) - { - charsWritten = Encoding.UTF8.GetChars(messageBytesPtr, messageBytes.Length, logMessageBufferPtr, logMessageBuffer.Length); - } - } - #endif textWriter.Write(logMessageBuffer, 0, charsWritten); } finally @@ -184,11 +171,7 @@ private static void WriteItem(Utf8JsonWriter writer, KeyValuePair + + + diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs index 9d99836c45b130..1d1f009c68450c 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs @@ -15,13 +15,9 @@ internal sealed class SimpleConsoleFormatter : ConsoleFormatter, IDisposable private const string LoglevelPadding = ": "; private static readonly string _messagePadding = new string(' ', GetLogLevelString(LogLevel.Information).Length + LoglevelPadding.Length); private static readonly string _newLineWithMessagePadding = Environment.NewLine + _messagePadding; -#if NET private static bool IsAndroidOrAppleMobile => OperatingSystem.IsAndroid() || OperatingSystem.IsTvOS() || OperatingSystem.IsIOS(); // returns true on MacCatalyst -#else - private static bool IsAndroidOrAppleMobile => false; -#endif private readonly IDisposable? _optionsReloadToken; public SimpleConsoleFormatter(IOptionsMonitor options) diff --git a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj index 42997baf5d8eae..8012c82c736ff6 100644 --- a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj +++ b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj @@ -167,6 +167,8 @@ The System.Collections.Immutable library is built-in as part of the shared frame + + diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs index 533d3bde2ad0bf..bcd183b74a4dc7 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs @@ -57,11 +57,7 @@ public static FrozenHashTable Create(Span hashCodes, bool hashCodesAreUniqu // into hashCodes of the head element of that bucket's chain. // - nexts: the ith element stores the index of the next item in the chain. // Use long to check for overflow before allocating - very large collections can overflow int. -#if NET if ((long)numBuckets + hashCodes.Length > Array.MaxLength) -#else - if ((long)numBuckets + hashCodes.Length > 0x7FFFFFC7) -#endif { throw new OutOfMemoryException(); } diff --git a/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs b/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs index 695058294a7a6f..a669f0a239f44a 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs @@ -1,23 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.ComponentModel; using System.Runtime.CompilerServices; namespace System.Collections.Generic { -#if !NET - internal static class KeyValuePairExtensions - { - [EditorBrowsable(EditorBrowsableState.Never)] - public static void Deconstruct(this KeyValuePair source, out TKey key, out TValue value) - { - key = source.Key; - value = source.Value; - } - } -#endif - #if !NET internal interface IReadOnlySet : IReadOnlyCollection { diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index a18b479fcea19c..ecdb05dc3eb4ff 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -132,6 +132,7 @@ System.Diagnostics.DiagnosticSource + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs index 09043dd5b0df6c..8a929365d5234d 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs @@ -267,14 +267,8 @@ public int MapToIndex(double value) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsFinite(double value) - { -#if NET - return double.IsFinite(value); -#else - return !double.IsInfinity(value) && !double.IsNaN(value); -#endif - } + private static bool IsFinite(double value) => + double.IsFinite(value); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LeadingZero64(long value) diff --git a/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj b/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj index 0a0b502728f9c4..e3642f29df5244 100644 --- a/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj +++ b/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj @@ -49,6 +49,8 @@ System.Formats.Cbor.CborWriter + + diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborConformanceLevel.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborConformanceLevel.cs index b46066f061a5bc..bddd4c9c018502 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborConformanceLevel.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborConformanceLevel.cs @@ -207,20 +207,7 @@ public static bool RequireCanonicalSimpleValueEncodings(CborConformanceMode conf public static int GetKeyEncodingHashCode(ReadOnlySpan encoding) { HashCode hash = default; -#if NET hash.AddBytes(encoding); -#else - while (encoding.Length >= sizeof(int)) - { - hash.Add(MemoryMarshal.Read(encoding)); - encoding = encoding.Slice(sizeof(int)); - } - - foreach (byte b in encoding) - { - hash.Add(b); - } -#endif return hash.ToHashCode(); } diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs index 245c5eb0d3f458..a3b4cd4470e6f1 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs @@ -38,11 +38,7 @@ public void WriteTag(CborTag tag) public void WriteDateTimeOffset(DateTimeOffset value) { string dateString = -#if NET value.TotalOffsetMinutes == 0 ? -#else - value.Offset == TimeSpan.Zero ? -#endif // NET value.UtcDateTime.ToString(Rfc3339FormatString, CultureInfo.InvariantCulture) : // prefer 'Z' over '+00:00' value.ToString(Rfc3339FormatString, CultureInfo.InvariantCulture); diff --git a/src/libraries/System.IO.Hashing/src/System.IO.Hashing.csproj b/src/libraries/System.IO.Hashing/src/System.IO.Hashing.csproj index 0a9790f49767db..c8767ed4b326fe 100644 --- a/src/libraries/System.IO.Hashing/src/System.IO.Hashing.csproj +++ b/src/libraries/System.IO.Hashing/src/System.IO.Hashing.csproj @@ -42,6 +42,7 @@ System.IO.Hashing.XxHash32 + diff --git a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/NonCryptographicHashAlgorithm.cs b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/NonCryptographicHashAlgorithm.cs index c9b9b0a6ba864a..1289b70496750d 100644 --- a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/NonCryptographicHashAlgorithm.cs +++ b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/NonCryptographicHashAlgorithm.cs @@ -127,9 +127,6 @@ public Task AppendAsync(Stream stream, CancellationToken cancellationToken = def return stream.CopyToAsync( new CopyToDestinationStream(this), -#if !NET - 81_920, // default size used by Stream.CopyTo{Async} -#endif cancellationToken); } diff --git a/src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs b/src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs index 8ea0dac7b1232d..12d95cd667750f 100644 --- a/src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs +++ b/src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs @@ -122,20 +122,7 @@ internal void PlayWaveFile(AudioData audio) { byte[] data = new byte[(int)audio._stream.Length]; -#if NET audio._stream.ReadExactly(data); -#else - int totalRead = 0; - while (totalRead < data.Length) - { - int bytesRead = audio._stream.Read(data, totalRead, data.Length - totalRead); - if (bytesRead <= 0) - { - throw new EndOfStreamException(); - } - totalRead += bytesRead; - } -#endif Play(data); } diff --git a/src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs b/src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs index efed2d9a07aecf..95e1a30859835e 100644 --- a/src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs +++ b/src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs @@ -176,20 +176,7 @@ public int Volume MemoryStream memStream = new(cLen); byte[] ab = new byte[cLen]; -#if NET stream.ReadExactly(ab); -#else - int totalRead = 0; - while (totalRead < cLen) - { - int bytesRead = stream.Read(ab, totalRead, cLen - totalRead); - if (bytesRead <= 0) - { - throw new EndOfStreamException(); - } - totalRead += bytesRead; - } -#endif _resourceLoader.UnloadFile(localPath); memStream.Write(ab, 0, cLen); diff --git a/src/libraries/System.Speech/src/System.Speech.csproj b/src/libraries/System.Speech/src/System.Speech.csproj index ab974973218280..76f1feb71ff35e 100644 --- a/src/libraries/System.Speech/src/System.Speech.csproj +++ b/src/libraries/System.Speech/src/System.Speech.csproj @@ -35,6 +35,7 @@ System.Speech.Recognition.SpeechRecognizer + diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index bd9a5dd0680aba..4096ba5db7ab6a 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -367,6 +367,9 @@ The System.Text.Json library is built-in as part of the shared framework in .NET + + + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs index b551ef4dee1a56..aab9b3364591fd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs @@ -247,23 +247,11 @@ public static Dictionary CreateDictionaryFromCollection + double.IsFinite(value); - public static bool IsFinite(float value) - { -#if NET - return float.IsFinite(value); -#else - return !(float.IsNaN(value) || float.IsInfinity(value)); -#endif - } + public static bool IsFinite(float value) => + float.IsFinite(value); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ValidateInt32MaxArrayLength(uint length) @@ -274,21 +262,6 @@ public static void ValidateInt32MaxArrayLength(uint length) } } -#if !NET - public static bool HasAllSet(this BitArray bitArray) - { - for (int i = 0; i < bitArray.Count; i++) - { - if (!bitArray[i]) - { - return false; - } - } - - return true; - } -#endif - /// /// Gets a Regex instance for recognizing integer representations of enums. /// diff --git a/src/libraries/System.Threading.RateLimiting/src/System.Threading.RateLimiting.csproj b/src/libraries/System.Threading.RateLimiting/src/System.Threading.RateLimiting.csproj index 8a42115792903d..f20f8228960737 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System.Threading.RateLimiting.csproj +++ b/src/libraries/System.Threading.RateLimiting/src/System.Threading.RateLimiting.csproj @@ -47,6 +47,7 @@ System.Threading.RateLimiting.RateLimitLease + diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimiterHelper.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimiterHelper.cs index 4fae65d1245a9a..e538fc720072dd 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimiterHelper.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimiterHelper.cs @@ -7,9 +7,6 @@ namespace System.Threading.RateLimiting { internal static class RateLimiterHelper { -#if !NET - private static readonly double TickFrequency = (double)TimeSpan.TicksPerSecond / Stopwatch.Frequency; -#endif public static TimeSpan? GetElapsedTime(long? startTimestamp) { if (startTimestamp is null) @@ -17,20 +14,12 @@ internal static class RateLimiterHelper return null; } -#if NET return Stopwatch.GetElapsedTime(startTimestamp.Value); -#else - return new((long)((Stopwatch.GetTimestamp() - startTimestamp.Value) * TickFrequency)); -#endif } public static TimeSpan GetElapsedTime(long startTimestamp, long endTimestamp) { -#if NET return Stopwatch.GetElapsedTime(startTimestamp, endTimestamp); -#else - return new((long)((endTimestamp - startTimestamp) * TickFrequency)); -#endif } } } From 878040dcaedf0095cb5dca8a52a5c2fa66e21436 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 03:12:27 +0200 Subject: [PATCH 02/19] Revert OperatingSystem polyfills, expand Array.MaxLength usage, inline IsFinite - Revert OperatingSystem.Is* polyfills (keep #if NET guards) - Replace more 0x7FFFFFC7 constants with Array.MaxLength via polyfill (FrozenHashTable 2nd occurrence, CborWriter, JsonDocument.MetadataDb) - Inline JsonHelpers.IsFinite into call sites (double.IsFinite/float.IsFinite) - Inline Base2ExponentialHistogramAggregator.IsFinite into call sites Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/Polyfills/OperatingSystemPolyfills.cs | 19 ------------------- ...t.Extensions.FileProviders.Physical.csproj | 4 ---- .../src/PhysicalFileProvider.cs | 2 ++ .../src/PhysicalFilesWatcher.cs | 2 ++ ...icrosoft.Extensions.Logging.Console.csproj | 1 - .../src/SimpleConsoleFormatter.cs | 7 ++++++- .../Collections/Frozen/FrozenHashTable.cs | 4 ---- .../Base2ExponentialHistogramAggregator.cs | 8 ++------ .../src/System.Formats.Cbor.csproj | 1 + .../System/Formats/Cbor/Writer/CborWriter.cs | 6 +----- .../src/System.Text.Json.csproj | 1 + .../Json/Document/JsonDocument.MetadataDb.cs | 9 +-------- .../src/System/Text/Json/JsonHelpers.cs | 6 ------ .../Text/Json/Reader/Utf8JsonReader.TryGet.cs | 4 ++-- .../Text/Json/Writer/JsonWriterHelper.cs | 4 ++-- 15 files changed, 20 insertions(+), 58 deletions(-) delete mode 100644 src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs diff --git a/src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs b/src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs deleted file mode 100644 index 3df265fb3df034..00000000000000 --- a/src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System -{ - /// Provides downlevel polyfills for static methods on . - internal static class OperatingSystemPolyfills - { - extension(OperatingSystem) - { - public static bool IsAndroid() => false; - public static bool IsBrowser() => false; - public static bool IsIOS() => false; - public static bool IsMacCatalyst() => false; - public static bool IsTvOS() => false; - public static bool IsWasi() => false; - } - } -} diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj index 83a966b155974d..ae7ebacc83bb92 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj @@ -20,10 +20,6 @@ Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" /> - - - - diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs index c7d9d6dffe2dc0..ede1b40f391a23 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs @@ -162,6 +162,7 @@ internal PhysicalFilesWatcher CreateFileWatcher() string root = PathUtils.EnsureTrailingSlash(Path.GetFullPath(Root)); FileSystemWatcher? watcher; +#if NET // For browser/iOS/tvOS we will proactively fallback to polling since FileSystemWatcher is not supported. if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()) || OperatingSystem.IsTvOS()) { @@ -170,6 +171,7 @@ internal PhysicalFilesWatcher CreateFileWatcher() watcher = null; } else +#endif { // When UsePollingFileWatcher & UseActivePolling are set, we won't use a FileSystemWatcher. watcher = UsePollingFileWatcher && UseActivePolling ? null : new FileSystemWatcher(root); diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs index 8e28f381fd4e98..64531c2eb7a0a8 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs @@ -84,10 +84,12 @@ public PhysicalFilesWatcher( if (fileSystemWatcher != null) { +#if NET if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()) || OperatingSystem.IsTvOS()) { throw new PlatformNotSupportedException(SR.Format(SR.FileSystemWatcher_PlatformNotSupported, typeof(FileSystemWatcher))); } +#endif _fileWatcher = fileSystemWatcher; _fileWatcher.IncludeSubdirectories = true; diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index 1fbdbd4a585029..926ff8d3f7c9c2 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -40,7 +40,6 @@ - diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs index 1d1f009c68450c..3771c500e995be 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs @@ -15,9 +15,14 @@ internal sealed class SimpleConsoleFormatter : ConsoleFormatter, IDisposable private const string LoglevelPadding = ": "; private static readonly string _messagePadding = new string(' ', GetLogLevelString(LogLevel.Information).Length + LoglevelPadding.Length); private static readonly string _newLineWithMessagePadding = Environment.NewLine + _messagePadding; - private static bool IsAndroidOrAppleMobile => OperatingSystem.IsAndroid() || + private static bool IsAndroidOrAppleMobile => +#if NET + OperatingSystem.IsAndroid() || OperatingSystem.IsTvOS() || OperatingSystem.IsIOS(); // returns true on MacCatalyst +#else + false; +#endif private readonly IDisposable? _optionsReloadToken; public SimpleConsoleFormatter(IOptionsMonitor options) diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs index bcd183b74a4dc7..e0f92afc819bab 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs @@ -186,11 +186,7 @@ private static int CalcNumBuckets(ReadOnlySpan hashCodes, bool hashCodesAre // If the minimum bucket count combined with hash codes exceeds array length limits, // skip the expensive collision-counting loop below — any bucket count it finds // would cause Create to fail. Fall back to the next prime above uniqueCodesCount. -#if NET if (minNumBuckets + hashCodes.Length > Array.MaxLength) -#else - if (minNumBuckets + hashCodes.Length > 0x7FFFFFC7) -#endif { return HashHelpers.GetPrime(uniqueCodesCount); } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs index 8a929365d5234d..d162b767882e8f 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs @@ -172,7 +172,7 @@ public override IAggregationStatistics Collect() public override void Update(double measurement) { - if (!IsFinite(measurement)) + if (!double.IsFinite(measurement)) { return; } @@ -232,7 +232,7 @@ public override void Update(double measurement) /// Returns the index of the bucket. public int MapToIndex(double value) { - Debug.Assert(IsFinite(value), "IEEE-754 +Inf, -Inf and NaN should be filtered out before calling this method."); + Debug.Assert(double.IsFinite(value), "IEEE-754 +Inf, -Inf and NaN should be filtered out before calling this method."); Debug.Assert(value != 0, "IEEE-754 zero values should be handled by ZeroCount."); Debug.Assert(value > 0, "IEEE-754 negative values should be normalized before calling this method."); @@ -266,10 +266,6 @@ public int MapToIndex(double value) } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsFinite(double value) => - double.IsFinite(value); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LeadingZero64(long value) { diff --git a/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj b/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj index e3642f29df5244..04dfc7a44cf491 100644 --- a/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj +++ b/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj @@ -51,6 +51,7 @@ System.Formats.Cbor.CborWriter + diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs index 12bf1f0a242b53..f233130cfef898 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs @@ -241,11 +241,7 @@ private void EnsureWriteCapacity(int pendingCount) if (currentCapacity < requiredCapacity) { int newCapacity = currentCapacity == 0 ? 1024 : currentCapacity * 2; - const uint MaxArrayLength = 0x7FFFFFC7; // Array.MaxLength -#if NET - Debug.Assert(MaxArrayLength == Array.MaxLength); -#endif - if ((uint)newCapacity > MaxArrayLength || newCapacity < requiredCapacity) + if ((uint)newCapacity > (uint)Array.MaxLength || newCapacity < requiredCapacity) { newCapacity = requiredCapacity; } diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 4096ba5db7ab6a..2d16113d4c7dc1 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -370,6 +370,7 @@ The System.Text.Json library is built-in as part of the shared framework in .NET + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs index 20cdf3775c0a43..87ee6ca78d751c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs @@ -237,17 +237,10 @@ private void Enlarge() byte[] toReturn = _data; // Allow the data to grow up to maximum possible capacity (~2G bytes) before encountering overflow. - // Note: Array.MaxLength exists only on .NET 6 or greater, - // so for the other versions value is hardcoded - const int MaxArrayLength = 0x7FFFFFC7; -#if NET - Debug.Assert(MaxArrayLength == Array.MaxLength); -#endif - int newCapacity = toReturn.Length * 2; // Note that this check works even when newCapacity overflowed thanks to the (uint) cast - if ((uint)newCapacity > MaxArrayLength) newCapacity = MaxArrayLength; + if ((uint)newCapacity > Array.MaxLength) newCapacity = Array.MaxLength; // If the maximum capacity has already been reached, // then set the new capacity to be larger than what is possible diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs index aab9b3364591fd..ccfc08e7b384cd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs @@ -247,12 +247,6 @@ public static Dictionary CreateDictionaryFromCollection - double.IsFinite(value); - - public static bool IsFinite(float value) => - float.IsFinite(value); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ValidateInt32MaxArrayLength(uint length) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.TryGet.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.TryGet.cs index bef69db6770c99..fa4427656868eb 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.TryGet.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.TryGet.cs @@ -605,7 +605,7 @@ internal float GetSingleWithQuotes() // The following logic reconciles the two implementations to enforce consistent behavior. if (!(Utf8Parser.TryParse(span, out value, out int bytesConsumed) && span.Length == bytesConsumed - && JsonHelpers.IsFinite(value))) + && float.IsFinite(value))) { ThrowHelper.ThrowFormatException(NumericType.Single); } @@ -662,7 +662,7 @@ internal double GetDoubleWithQuotes() // The following logic reconciles the two implementations to enforce consistent behavior. if (!(Utf8Parser.TryParse(span, out value, out int bytesConsumed) && span.Length == bytesConsumed - && JsonHelpers.IsFinite(value))) + && double.IsFinite(value))) { ThrowHelper.ThrowFormatException(NumericType.Double); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index 38ff45cde115ff..c69d78ed5c6fbb 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -78,7 +78,7 @@ public static void ValidateValue(ReadOnlySpan value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ValidateDouble(double value) { - if (!JsonHelpers.IsFinite(value)) + if (!double.IsFinite(value)) { ThrowHelper.ThrowArgumentException_ValueNotSupported(); } @@ -87,7 +87,7 @@ public static void ValidateDouble(double value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ValidateSingle(float value) { - if (!JsonHelpers.IsFinite(value)) + if (!float.IsFinite(value)) { ThrowHelper.ThrowArgumentException_ValueNotSupported(); } From fd718d63ede03095a0178e659dbce145e2fff9cf Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 03:15:25 +0200 Subject: [PATCH 03/19] Move Immutable Polyfills.cs to Common/src/Polyfills/ Split into IReadOnlySetPolyfill.cs and BitOperationsPolyfill.cs. Both use #if !NET guards since the types don't exist on downlevel. Update both src and test csproj references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/Polyfills/BitOperationsPolyfill.cs | 17 +++++++++++++++++ .../src/Polyfills/IReadOnlySetPolyfill.cs} | 13 +------------ .../src/System.Collections.Immutable.csproj | 3 ++- .../System.Collections.Immutable.Tests.csproj | 4 +++- 4 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 src/libraries/Common/src/Polyfills/BitOperationsPolyfill.cs rename src/libraries/{System.Collections.Immutable/src/System/Polyfills.cs => Common/src/Polyfills/IReadOnlySetPolyfill.cs} (66%) diff --git a/src/libraries/Common/src/Polyfills/BitOperationsPolyfill.cs b/src/libraries/Common/src/Polyfills/BitOperationsPolyfill.cs new file mode 100644 index 00000000000000..acaa2316746328 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/BitOperationsPolyfill.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if !NET + +using System.Runtime.CompilerServices; + +namespace System.Numerics +{ + internal static class BitOperations + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) => (value << offset) | (value >> (32 - offset)); + } +} + +#endif diff --git a/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs b/src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs similarity index 66% rename from src/libraries/System.Collections.Immutable/src/System/Polyfills.cs rename to src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs index a669f0a239f44a..a52f237c7f4b0f 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs +++ b/src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs @@ -1,11 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Runtime.CompilerServices; +#if !NET namespace System.Collections.Generic { -#if !NET internal interface IReadOnlySet : IReadOnlyCollection { bool Contains(T item); @@ -16,16 +15,6 @@ internal interface IReadOnlySet : IReadOnlyCollection bool Overlaps(IEnumerable other); bool SetEquals(IEnumerable other); } -#endif } -namespace System.Numerics -{ -#if !NET - internal static class BitOperations - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint RotateLeft(uint value, int offset) => (value << offset) | (value >> (32 - offset)); - } #endif -} diff --git a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj index 8012c82c736ff6..14fd59e3684850 100644 --- a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj +++ b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj @@ -12,7 +12,6 @@ The System.Collections.Immutable library is built-in as part of the shared frame - @@ -169,6 +168,8 @@ The System.Collections.Immutable library is built-in as part of the shared frame + + diff --git a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj index 1cf4a9af0f02ba..d0c832aa5ce022 100644 --- a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj +++ b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj @@ -18,7 +18,9 @@ - + + + From f5429bafc0e799cdd4f1dd7e0b8ac6ef84b7703b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 03:52:17 +0200 Subject: [PATCH 04/19] Move Reflection.Metadata Polyfills.cs to Common/src/Polyfills/ Split into BitConverterPolyfills.cs and GuidPolyfills.cs for reuse across libraries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/Polyfills/BitConverterPolyfills.cs | 28 +++++++++++++++++++ .../src/Polyfills/GuidPolyfills.cs} | 23 +-------------- .../src/System.Reflection.Metadata.csproj | 3 +- 3 files changed, 31 insertions(+), 23 deletions(-) create mode 100644 src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs rename src/libraries/{System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/Polyfills.cs => Common/src/Polyfills/GuidPolyfills.cs} (64%) diff --git a/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs b/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs new file mode 100644 index 00000000000000..e597f17c02a2f2 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System +{ + /// Provides downlevel polyfills for static methods on . + internal static class BitConverterPolyfills + { + extension(BitConverter) + { + public static uint SingleToUInt32Bits(float value) + { + unsafe + { + return *(uint*)&value; + } + } + + public static ulong DoubleToUInt64Bits(double value) + { + unsafe + { + return *(ulong*)&value; + } + } + } + } +} diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/Polyfills.cs b/src/libraries/Common/src/Polyfills/GuidPolyfills.cs similarity index 64% rename from src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/Polyfills.cs rename to src/libraries/Common/src/Polyfills/GuidPolyfills.cs index 8c91c9ff15f59e..7304b2dbc33155 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/Polyfills.cs +++ b/src/libraries/Common/src/Polyfills/GuidPolyfills.cs @@ -6,28 +6,7 @@ namespace System { - internal static class BitConverterPolyfills - { - extension(BitConverter) - { - public static uint SingleToUInt32Bits(float value) - { - unsafe - { - return *(uint*)&value; - } - } - - public static ulong DoubleToUInt64Bits(double value) - { - unsafe - { - return *(ulong*)&value; - } - } - } - } - + /// Provides downlevel polyfills for instance methods on . internal static class GuidPolyfills { extension(Guid self) diff --git a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj index 242a4c1f6a6f54..9cb8b293db3b83 100644 --- a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj +++ b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj @@ -93,7 +93,8 @@ The System.Reflection.Metadata library is built-in as part of the shared framewo - + + From cf145c997322364db9d366deb0cbb99a58f6ae8a Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 04:17:03 +0200 Subject: [PATCH 05/19] Apply existing polyfills to more libraries Leverage polyfills already in Common/src/Polyfills/ to remove #if NET blocks across additional libraries: - ArrayPolyfills: LengthBuckets.cs, ArrayInfo.cs (Nrbf) - IReadOnlySetPolyfill: ImmutableSortedSet, ImmutableHashSet, FrozenSet - StreamPolyfills: SoundPlayer.cs, XmlBuffer.cs (Syndication) - DateTimeOffsetPolyfills: CacheEntry.cs, Rss20FeedFormatter, Atom10FeedFormatter - HashCodePolyfills: CoseHeaderValue.cs - EnvironmentPolyfills: Win32.cs (Hosting.WindowsServices), SystemdHelpers.cs cleanup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/CacheEntry.cs | 4 ---- .../src/Microsoft.Extensions.Caching.Memory.csproj | 3 +++ .../src/SystemdHelpers.cs | 3 --- .../src/Internal/Win32.cs | 7 +------ ...rosoft.Extensions.Hosting.WindowsServices.csproj | 4 ++++ .../src/System/Collections/Frozen/FrozenSet.cs | 2 -- .../Collections/Frozen/String/LengthBuckets.cs | 4 ---- .../Collections/Immutable/ImmutableHashSet_1.cs | 4 ---- .../Collections/Immutable/ImmutableSortedSet_1.cs | 4 ---- .../src/System.Formats.Nrbf.csproj | 1 + .../src/System/Formats/Nrbf/ArrayInfo.cs | 6 +----- .../src/System.Security.Cryptography.Cose.csproj | 1 + .../Security/Cryptography/Cose/CoseHeaderValue.cs | 7 ------- .../src/System.ServiceModel.Syndication.csproj | 5 +++++ .../ServiceModel/Syndication/Atom10FeedFormatter.cs | 4 ---- .../ServiceModel/Syndication/Rss20FeedFormatter.cs | 4 ---- .../src/System/ServiceModel/XmlBuffer.cs | 13 ------------- .../src/System.Windows.Extensions.csproj | 4 ++++ .../src/System/Media/SoundPlayer.cs | 13 ------------- 19 files changed, 20 insertions(+), 73 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/CacheEntry.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/src/CacheEntry.cs index 96b7daed712118..c7a413975f812b 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/CacheEntry.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/CacheEntry.cs @@ -84,11 +84,7 @@ internal long AbsoluteExpirationTicks { DateTimeOffset expiration = value.GetValueOrDefault(); _absoluteExpirationTicks = expiration.UtcTicks; -#if NET _absoluteExpirationOffsetMinutes = (short)expiration.TotalOffsetMinutes; -#else - _absoluteExpirationOffsetMinutes = (short)(expiration.Offset.Ticks / TimeSpan.TicksPerMinute); -#endif } } } diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj index f6d2ac8dc8065c..1ca676e3dee506 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj @@ -23,5 +23,8 @@ + + + diff --git a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs index 84e5fffffb10a7..3b8259bd799234 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs @@ -5,9 +5,6 @@ using System.Globalization; using System.IO; using System.Text; -#if !NET -using System.Diagnostics; -#endif namespace Microsoft.Extensions.Hosting.Systemd { diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Internal/Win32.cs b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Internal/Win32.cs index b886b87f6350e0..fb8d77c5585b77 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Internal/Win32.cs +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Internal/Win32.cs @@ -23,12 +23,7 @@ internal static class Win32 procEntry.dwSize = sizeof(Interop.Kernel32.PROCESSENTRY32); if (Interop.Kernel32.Process32First(snapshotHandle, &procEntry)) { - int currentProcessId = -#if NET - Environment.ProcessId; -#else - Process.GetCurrentProcess().Id; -#endif + int currentProcessId = Environment.ProcessId; do { if (currentProcessId == procEntry.th32ProcessID) diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Microsoft.Extensions.Hosting.WindowsServices.csproj b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Microsoft.Extensions.Hosting.WindowsServices.csproj index 4194664608c32e..a8008eca3475c5 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Microsoft.Extensions.Hosting.WindowsServices.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Microsoft.Extensions.Hosting.WindowsServices.csproj @@ -24,6 +24,10 @@ Link="Common\DisableRuntimeMarshalling.cs" /> + + + + diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs index bbb50ce77de737..878ad47a9268dd 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs @@ -238,9 +238,7 @@ private static FrozenSet CreateFromSet(HashSet source) [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] [DebuggerDisplay("Count = {Count}")] public abstract partial class FrozenSet : ISet, -#if NET IReadOnlySet, -#endif IReadOnlyCollection, ICollection { /// Initialize the set. diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBuckets.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBuckets.cs index ac2f17bca8372e..680c6ba2d5fbaa 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBuckets.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBuckets.cs @@ -28,11 +28,7 @@ internal static class LengthBuckets } long expectedArraySize = (long)spread * MaxPerLength; -#if NET if (expectedArraySize > Array.MaxLength) -#else - if (expectedArraySize > 0X7FFFFFC7) -#endif { // In the future we may lower the value, as it may be quite unlikely // to have a LOT of strings of different sizes. diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs index c6b6f3140e4cc2..781e472f82b62b 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs @@ -15,11 +15,7 @@ namespace System.Collections.Immutable [CollectionBuilder(typeof(ImmutableHashSet), nameof(ImmutableHashSet.Create))] [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] -#if NET public sealed partial class ImmutableHashSet : IImmutableSet, IReadOnlyCollection, ICollection, ISet, IReadOnlySet, ICollection, IStrongEnumerable.Enumerator> -#else - public sealed partial class ImmutableHashSet : IImmutableSet, IReadOnlyCollection, ICollection, ISet, ICollection, IStrongEnumerable.Enumerator> -#endif { /// /// An empty immutable hash set with the default comparer for . diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs index 902e9168872cf4..aa12869f2430a8 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs @@ -20,11 +20,7 @@ namespace System.Collections.Immutable [CollectionBuilder(typeof(ImmutableSortedSet), nameof(ImmutableSortedSet.Create))] [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] -#if NET public sealed partial class ImmutableSortedSet : IImmutableSet, IReadOnlySet, IReadOnlyList, IList, ISet, IList, IStrongEnumerable.Enumerator> -#else - public sealed partial class ImmutableSortedSet : IImmutableSet, IReadOnlyList, IList, ISet, IList, IStrongEnumerable.Enumerator> -#endif { /// /// This is the factor between the small collection's size and the large collection's size in a bulk operation, diff --git a/src/libraries/System.Formats.Nrbf/src/System.Formats.Nrbf.csproj b/src/libraries/System.Formats.Nrbf/src/System.Formats.Nrbf.csproj index 056aa832e7d927..7be11b59ad80f2 100644 --- a/src/libraries/System.Formats.Nrbf/src/System.Formats.Nrbf.csproj +++ b/src/libraries/System.Formats.Nrbf/src/System.Formats.Nrbf.csproj @@ -17,5 +17,6 @@ + diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs index dd045f7cd9e483..48527dee991541 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs @@ -16,11 +16,7 @@ namespace System.Formats.Nrbf; [DebuggerDisplay("{ArrayType}, rank={Rank}")] internal readonly struct ArrayInfo { -#if NET - internal static int MaxArrayLength => Array.MaxLength; // dynamic lookup in case the value changes in a future runtime -#else - internal const int MaxArrayLength = 2147483591; // hardcode legacy Array.MaxLength for downlevel runtimes -#endif + internal static int MaxArrayLength => Array.MaxLength; internal ArrayInfo(SerializationRecordId id, long totalElementsCount, BinaryArrayType arrayType = BinaryArrayType.Single, int rank = 1) { diff --git a/src/libraries/System.Security.Cryptography.Cose/src/System.Security.Cryptography.Cose.csproj b/src/libraries/System.Security.Cryptography.Cose/src/System.Security.Cryptography.Cose.csproj index a448ec9e6322be..b2b23ba884f621 100644 --- a/src/libraries/System.Security.Cryptography.Cose/src/System.Security.Cryptography.Cose.csproj +++ b/src/libraries/System.Security.Cryptography.Cose/src/System.Security.Cryptography.Cose.csproj @@ -56,6 +56,7 @@ + diff --git a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseHeaderValue.cs b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseHeaderValue.cs index 3be45eca1a9bbf..a87d20454bcb28 100644 --- a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseHeaderValue.cs +++ b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseHeaderValue.cs @@ -252,14 +252,7 @@ public int GetValueAsBytes(Span destination) public override int GetHashCode() { HashCode hashCode = default; -#if NET hashCode.AddBytes(EncodedValue.Span); -#else - foreach (byte b in EncodedValue.Span) - { - hashCode.Add(b); - } -#endif return hashCode.ToHashCode(); } diff --git a/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj b/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj index c5f32e4efda4cb..be54549f6ff28a 100644 --- a/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj +++ b/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj @@ -67,4 +67,9 @@ + + + + + diff --git a/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs b/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs index 966fd0feaf097b..37e5cd5c150aa8 100644 --- a/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs +++ b/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs @@ -573,11 +573,7 @@ private static TextSyndicationContent ReadTextContentFromHelper(XmlReader reader private static string AsString(DateTimeOffset dateTime) { -#if NET if (dateTime.TotalOffsetMinutes == 0) -#else - if (dateTime.Offset == TimeSpan.Zero) -#endif // NET { return dateTime.ToUniversalTime().ToString(Rfc3339UTCDateTimeFormat, CultureInfo.InvariantCulture); } diff --git a/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs b/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs index f8788e4b4cff7b..d6017df5aec154 100644 --- a/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs +++ b/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs @@ -174,11 +174,7 @@ protected virtual void WriteItems(XmlWriter writer, IEnumerable private static string AsString(DateTimeOffset dateTime) { -#if NET if (dateTime.TotalOffsetMinutes == 0) -#else - if (dateTime.Offset == TimeSpan.Zero) -#endif // NET { return dateTime.ToUniversalTime().ToString(Rfc822OutputUtcDateTimeFormat, CultureInfo.InvariantCulture); } diff --git a/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/XmlBuffer.cs b/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/XmlBuffer.cs index 4c31f32bf505a2..7a1b4a28f171e5 100644 --- a/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/XmlBuffer.cs +++ b/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/XmlBuffer.cs @@ -87,20 +87,7 @@ public void Close() _buffer = new byte[_stream.Length]; _stream.Position = 0; -#if NET _stream.ReadExactly(_buffer); -#else - int totalRead = 0; - while (totalRead < _buffer.Length) - { - int bytesRead = _stream.Read(_buffer, totalRead, _buffer.Length - totalRead); - if (bytesRead <= 0) - { - throw new EndOfStreamException(); - } - totalRead += bytesRead; - } -#endif _writer = null; _stream = null; diff --git a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj index d55312a08d6c53..fc43462e83ff0b 100644 --- a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj +++ b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj @@ -92,6 +92,10 @@ System.Security.Cryptography.X509Certificates.X509SelectionFlag + + + + diff --git a/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs b/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs index cf0189a9b47c30..989744c3269d2f 100644 --- a/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs +++ b/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs @@ -314,20 +314,7 @@ private void LoadStream(bool loadSync) int streamLen = (int)_stream.Length; _currentPos = 0; _streamData = new byte[streamLen]; -#if NET _stream.ReadExactly(_streamData); -#else - int totalRead = 0; - while (totalRead < streamLen) - { - int bytesRead = _stream.Read(_streamData, totalRead, streamLen - totalRead); - if (bytesRead <= 0) - { - throw new EndOfStreamException(); - } - totalRead += bytesRead; - } -#endif IsLoadCompleted = true; OnLoadCompleted(new AsyncCompletedEventArgs(null, false, null)); } From 672bbabb9ef11ca1e33e4df659bdc0602398f29c Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 04:49:10 +0200 Subject: [PATCH 06/19] Address PR feedback - EnvironmentPolyfills: dispose Process instance to avoid handle leak - DoublePolyfills/SinglePolyfills: use same bit-manipulation impl as the real Double.IsFinite/Single.IsFinite in CoreLib - IReadOnlySetPolyfill: add comment explaining why #if !NET is needed - StreamPolyfills: add comment explaining the 81_920 buffer size constant Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/libraries/Common/src/Polyfills/DoublePolyfills.cs | 10 ++++++++-- .../Common/src/Polyfills/EnvironmentPolyfills.cs | 9 ++++++++- .../Common/src/Polyfills/IReadOnlySetPolyfill.cs | 5 +++++ src/libraries/Common/src/Polyfills/SinglePolyfills.cs | 10 ++++++++-- src/libraries/Common/src/Polyfills/StreamPolyfills.cs | 2 +- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/libraries/Common/src/Polyfills/DoublePolyfills.cs b/src/libraries/Common/src/Polyfills/DoublePolyfills.cs index 51608461f2fcb7..86d2444f6994fd 100644 --- a/src/libraries/Common/src/Polyfills/DoublePolyfills.cs +++ b/src/libraries/Common/src/Polyfills/DoublePolyfills.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + namespace System { /// Provides downlevel polyfills for static methods on . @@ -8,8 +10,12 @@ internal static class DoublePolyfills { extension(double) { - public static bool IsFinite(double value) => - !(double.IsNaN(value) || double.IsInfinity(value)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsFinite(double d) + { + long bits = BitConverter.DoubleToInt64Bits(d); + return ((ulong)~bits & 0x7FF0_0000_0000_0000UL) != 0; + } } } } diff --git a/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs b/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs index e168c3720a27d2..e32970b4e462c0 100644 --- a/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs @@ -10,7 +10,14 @@ internal static class EnvironmentPolyfills { extension(Environment) { - public static int ProcessId => Process.GetCurrentProcess().Id; + public static int ProcessId + { + get + { + using Process currentProcess = Process.GetCurrentProcess(); + return currentProcess.Id; + } + } } } } diff --git a/src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs b/src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs index a52f237c7f4b0f..f8f7638a60485c 100644 --- a/src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs +++ b/src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs @@ -1,6 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// This file defines the IReadOnlySet interface for downlevel targets +// where it doesn't exist. Unlike extension()-based polyfills, this uses +// #if !NET because the entire type is missing on netstandard2.0 — there +// is nothing to extend. + #if !NET namespace System.Collections.Generic diff --git a/src/libraries/Common/src/Polyfills/SinglePolyfills.cs b/src/libraries/Common/src/Polyfills/SinglePolyfills.cs index f4dc02e7f65402..b2af28b3bbd60e 100644 --- a/src/libraries/Common/src/Polyfills/SinglePolyfills.cs +++ b/src/libraries/Common/src/Polyfills/SinglePolyfills.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + namespace System { /// Provides downlevel polyfills for static methods on . @@ -8,8 +10,12 @@ internal static class SinglePolyfills { extension(float) { - public static bool IsFinite(float value) => - !(float.IsNaN(value) || float.IsInfinity(value)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool IsFinite(float f) + { + uint bits = *(uint*)&f; + return (~bits & 0x7F80_0000U) != 0; + } } } } diff --git a/src/libraries/Common/src/Polyfills/StreamPolyfills.cs b/src/libraries/Common/src/Polyfills/StreamPolyfills.cs index 798633266c73a0..4e918b8de54f86 100644 --- a/src/libraries/Common/src/Polyfills/StreamPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/StreamPolyfills.cs @@ -27,7 +27,7 @@ public void ReadExactly(byte[] buffer) } public Task CopyToAsync(Stream destination, CancellationToken cancellationToken) => - stream.CopyToAsync(destination, 81_920, cancellationToken); + stream.CopyToAsync(destination, 81_920, cancellationToken); // 81_920 is the default buffer size used by Stream.CopyToAsync on .NET } } } From b7fd6b1c8273683e4f2a1983597464489523e7ea Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 04:54:40 +0200 Subject: [PATCH 07/19] Add RuntimeHelpersPolyfills, clean up STJ #if NET blocks New polyfill: RuntimeHelpersPolyfills.cs provides: - TryEnsureSufficientExecutionStack (wraps EnsureSufficientExecutionStack) - GetUninitializedObject (delegates to FormatterServices) Cleaned up in System.Text.Json: - StackHelper.cs: remove #if NET for TryEnsureSufficientExecutionStack - FSharpUnionConverter.cs: remove #if NET for GetUninitializedObject and dead conditional using Skipped (not polyfillable with extension() blocks): - JsonArray.cs: List.AddRange(ReadOnlySpan) and uint.TryFormat - CharConverter.cs: new ReadOnlySpan(in value) constructor - JsonCamelCaseNamingPolicy.cs: string.Create (shared with generators) - JsonReaderHelper.Unescaping.cs: Utf8.IsValid (different error handling) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/Polyfills/RuntimeHelpersPolyfills.cs | 34 +++++++++++++++++++ .../src/System.Text.Json.csproj | 1 + .../Converters/FSharp/FSharpUnionConverter.cs | 7 ---- .../src/System/Text/Json/StackHelper.cs | 12 ------- 4 files changed, 35 insertions(+), 19 deletions(-) create mode 100644 src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs diff --git a/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs b/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs new file mode 100644 index 00000000000000..04aa1f421d4776 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +namespace System.Runtime.CompilerServices +{ + /// Provides downlevel polyfills for static methods on . + internal static class RuntimeHelpersPolyfills + { + extension(RuntimeHelpers) + { + public static bool TryEnsureSufficientExecutionStack() + { + try + { + RuntimeHelpers.EnsureSufficientExecutionStack(); + return true; + } + catch + { + return false; + } + } + + public static object GetUninitializedObject(Type type) + { +#pragma warning disable SYSLIB0050 // FormatterServices.GetUninitializedObject is obsolete + return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); +#pragma warning restore SYSLIB0050 + } + } + } +} diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 2d16113d4c7dc1..68849e5833fea9 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -371,6 +371,7 @@ The System.Text.Json library is built-in as part of the shared framework in .NET + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/FSharp/FSharpUnionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/FSharp/FSharpUnionConverter.cs index f4818ccb690f1c..8525196eb7ceda 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/FSharp/FSharpUnionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/FSharp/FSharpUnionConverter.cs @@ -7,9 +7,6 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; -#if !NET -using System.Runtime.Serialization; -#endif using System.Text.Json.Reflection; using System.Text.Json.Serialization.Metadata; @@ -104,11 +101,7 @@ public FSharpUnionConverter( { Type fieldType = fields[i].FieldType; defaultFieldValues[i] = fieldType.IsValueType ? -#if NET RuntimeHelpers.GetUninitializedObject(fieldType) : -#else - FormatterServices.GetUninitializedObject(fieldType) : -#endif null!; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/StackHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/StackHelper.cs index b3c6530dec0700..96e0e8c61a7dc3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/StackHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/StackHelper.cs @@ -11,19 +11,7 @@ internal static class StackHelper /// Tries to ensure there is sufficient stack to execute the average .NET function. public static bool TryEnsureSufficientExecutionStack() { -#if NET return RuntimeHelpers.TryEnsureSufficientExecutionStack(); -#else - try - { - RuntimeHelpers.EnsureSufficientExecutionStack(); - return true; - } - catch - { - return false; - } -#endif } } } From dab7861f6632a56de715ce461448f93da48171ae Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 16:21:04 +0200 Subject: [PATCH 08/19] Address PR review feedback - Fix stray carriage return in Caching.Memory csproj - JsonConsoleFormatter: use stackalloc span for char writing instead of ToString() to avoid allocation regression (copilot review) - Delete StackHelper.cs, inline RuntimeHelpers.TryEnsureSufficientExecutionStack call directly in JsonElement.cs (jkotas) - Revert IReadOnlySet polyfill: restore #if NET guards on FrozenSet, ImmutableHashSet, ImmutableSortedSet; keep IReadOnlySet definition in library-local Polyfills.cs (jkotas concern about subtle bugs) - Rename BitOperationsPolyfill.cs -> BitOperationsPolyfills.cs for consistent plural naming across all polyfill files - Remove dead StreamPolyfills ref from System.Windows.Extensions (only targets NETCoreApp, polyfill would never compile) - Fix EncodingPolyfills Link path for directory structure consistency Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...onsPolyfill.cs => BitOperationsPolyfills.cs} | 0 .../Microsoft.Extensions.Caching.Memory.csproj | 3 ++- .../src/JsonConsoleFormatter.cs | 4 +++- .../Microsoft.Extensions.Logging.Console.csproj | 2 +- .../src/System.Collections.Immutable.csproj | 6 +++--- .../src/System/Collections/Frozen/FrozenSet.cs | 2 ++ .../Collections/Immutable/ImmutableHashSet_1.cs | 4 ++++ .../Immutable/ImmutableSortedSet_1.cs | 4 ++++ .../src/System/Polyfills.cs} | 11 ++--------- .../System.Collections.Immutable.Tests.csproj | 4 ++-- .../src/System.Text.Json.csproj | 1 - .../System/Text/Json/Document/JsonElement.cs | 2 +- .../src/System/Text/Json/StackHelper.cs | 17 ----------------- .../src/System.Windows.Extensions.csproj | 4 ---- 14 files changed, 24 insertions(+), 40 deletions(-) rename src/libraries/Common/src/Polyfills/{BitOperationsPolyfill.cs => BitOperationsPolyfills.cs} (100%) rename src/libraries/{Common/src/Polyfills/IReadOnlySetPolyfill.cs => System.Collections.Immutable/src/System/Polyfills.cs} (70%) delete mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/StackHelper.cs diff --git a/src/libraries/Common/src/Polyfills/BitOperationsPolyfill.cs b/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs similarity index 100% rename from src/libraries/Common/src/Polyfills/BitOperationsPolyfill.cs rename to src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj index 1ca676e3dee506..84db14ff522588 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj @@ -23,7 +23,8 @@ - + + diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs index ecee8974578483..445fbb8fb74e33 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs @@ -171,7 +171,9 @@ private static void WriteItem(Utf8JsonWriter writer, KeyValuePair charSpan = stackalloc char[1]; + charSpan[0] = charValue; + writer.WriteString(key, charSpan); break; case decimal decimalValue: writer.WriteNumber(key, decimalValue); diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index 926ff8d3f7c9c2..b2a70123868cc3 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -40,7 +40,7 @@ - + diff --git a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj index 14fd59e3684850..af568a93a25513 100644 --- a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj +++ b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) @@ -12,6 +12,7 @@ The System.Collections.Immutable library is built-in as part of the shared frame + @@ -168,8 +169,7 @@ The System.Collections.Immutable library is built-in as part of the shared frame - - + diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs index 878ad47a9268dd..bbb50ce77de737 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs @@ -238,7 +238,9 @@ private static FrozenSet CreateFromSet(HashSet source) [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] [DebuggerDisplay("Count = {Count}")] public abstract partial class FrozenSet : ISet, +#if NET IReadOnlySet, +#endif IReadOnlyCollection, ICollection { /// Initialize the set. diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs index 781e472f82b62b..c6b6f3140e4cc2 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs @@ -15,7 +15,11 @@ namespace System.Collections.Immutable [CollectionBuilder(typeof(ImmutableHashSet), nameof(ImmutableHashSet.Create))] [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] +#if NET public sealed partial class ImmutableHashSet : IImmutableSet, IReadOnlyCollection, ICollection, ISet, IReadOnlySet, ICollection, IStrongEnumerable.Enumerator> +#else + public sealed partial class ImmutableHashSet : IImmutableSet, IReadOnlyCollection, ICollection, ISet, ICollection, IStrongEnumerable.Enumerator> +#endif { /// /// An empty immutable hash set with the default comparer for . diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs index aa12869f2430a8..902e9168872cf4 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs @@ -20,7 +20,11 @@ namespace System.Collections.Immutable [CollectionBuilder(typeof(ImmutableSortedSet), nameof(ImmutableSortedSet.Create))] [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] +#if NET public sealed partial class ImmutableSortedSet : IImmutableSet, IReadOnlySet, IReadOnlyList, IList, ISet, IList, IStrongEnumerable.Enumerator> +#else + public sealed partial class ImmutableSortedSet : IImmutableSet, IReadOnlyList, IList, ISet, IList, IStrongEnumerable.Enumerator> +#endif { /// /// This is the factor between the small collection's size and the large collection's size in a bulk operation, diff --git a/src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs b/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs similarity index 70% rename from src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs rename to src/libraries/System.Collections.Immutable/src/System/Polyfills.cs index f8f7638a60485c..1468f1623f4df6 100644 --- a/src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs @@ -1,15 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// This file defines the IReadOnlySet interface for downlevel targets -// where it doesn't exist. Unlike extension()-based polyfills, this uses -// #if !NET because the entire type is missing on netstandard2.0 — there -// is nothing to extend. - -#if !NET - namespace System.Collections.Generic { +#if !NET internal interface IReadOnlySet : IReadOnlyCollection { bool Contains(T item); @@ -20,6 +14,5 @@ internal interface IReadOnlySet : IReadOnlyCollection bool Overlaps(IEnumerable other); bool SetEquals(IEnumerable other); } -} - #endif +} diff --git a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj index d0c832aa5ce022..2ebee16aa5df48 100644 --- a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj +++ b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 68849e5833fea9..964cbb77d4425f 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -167,7 +167,6 @@ The System.Text.Json library is built-in as part of the shared framework in .NET - diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs index d791f189607e41..27cd31fd85fa40 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs @@ -1257,7 +1257,7 @@ internal ReadOnlySpan ValueSpan /// public static bool DeepEquals(JsonElement element1, JsonElement element2) { - if (!StackHelper.TryEnsureSufficientExecutionStack()) + if (!RuntimeHelpers.TryEnsureSufficientExecutionStack()) { ThrowHelper.ThrowInsufficientExecutionStackException_JsonElementDeepEqualsInsufficientExecutionStack(); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/StackHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/StackHelper.cs deleted file mode 100644 index 96e0e8c61a7dc3..00000000000000 --- a/src/libraries/System.Text.Json/src/System/Text/Json/StackHelper.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; - -namespace System.Text.Json -{ - /// Provides tools for avoiding stack overflows. - internal static class StackHelper - { - /// Tries to ensure there is sufficient stack to execute the average .NET function. - public static bool TryEnsureSufficientExecutionStack() - { - return RuntimeHelpers.TryEnsureSufficientExecutionStack(); - } - } -} diff --git a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj index fc43462e83ff0b..d55312a08d6c53 100644 --- a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj +++ b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj @@ -92,10 +92,6 @@ System.Security.Cryptography.X509Certificates.X509SelectionFlag - - - - From 52771e281cabaef9fab2bf8d2c2eefb3a53768ed Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 16:36:00 +0200 Subject: [PATCH 09/19] Revert SimpleConsoleFormatter.cs, use collection literal for char span - Fully revert all changes to SimpleConsoleFormatter.cs - JsonConsoleFormatter: use [charValue] collection literal instead of stackalloc + manual assignment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/JsonConsoleFormatter.cs | 4 +--- .../src/SimpleConsoleFormatter.cs | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs index 445fbb8fb74e33..040a4d09ae7fb7 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs @@ -171,9 +171,7 @@ private static void WriteItem(Utf8JsonWriter writer, KeyValuePair charSpan = stackalloc char[1]; - charSpan[0] = charValue; - writer.WriteString(key, charSpan); + writer.WriteString(key, [charValue]); break; case decimal decimalValue: writer.WriteNumber(key, decimalValue); diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs index 3771c500e995be..9d99836c45b130 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs @@ -15,13 +15,12 @@ internal sealed class SimpleConsoleFormatter : ConsoleFormatter, IDisposable private const string LoglevelPadding = ": "; private static readonly string _messagePadding = new string(' ', GetLogLevelString(LogLevel.Information).Length + LoglevelPadding.Length); private static readonly string _newLineWithMessagePadding = Environment.NewLine + _messagePadding; - private static bool IsAndroidOrAppleMobile => #if NET - OperatingSystem.IsAndroid() || + private static bool IsAndroidOrAppleMobile => OperatingSystem.IsAndroid() || OperatingSystem.IsTvOS() || OperatingSystem.IsIOS(); // returns true on MacCatalyst #else - false; + private static bool IsAndroidOrAppleMobile => false; #endif private readonly IDisposable? _optionsReloadToken; From e4fefc43cb6d2bb362c83e3c52950925eafc367f Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 17:16:33 +0200 Subject: [PATCH 10/19] Revert DiagnosticSource polyfill change (net481 CI uses VS MSBuild) The Libraries_NET481 CI leg fails because extension() blocks on primitive types may not resolve correctly under the VS MSBuild toolchain. Restore the original #if NET / #else pattern for Base2ExponentialHistogramAggregator.IsFinite. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/System.Diagnostics.DiagnosticSource.csproj | 1 - .../Metrics/Base2ExponentialHistogramAggregator.cs | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index ecdb05dc3eb4ff..a18b479fcea19c 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -132,7 +132,6 @@ System.Diagnostics.DiagnosticSource - diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs index d162b767882e8f..09043dd5b0df6c 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs @@ -172,7 +172,7 @@ public override IAggregationStatistics Collect() public override void Update(double measurement) { - if (!double.IsFinite(measurement)) + if (!IsFinite(measurement)) { return; } @@ -232,7 +232,7 @@ public override void Update(double measurement) /// Returns the index of the bucket. public int MapToIndex(double value) { - Debug.Assert(double.IsFinite(value), "IEEE-754 +Inf, -Inf and NaN should be filtered out before calling this method."); + Debug.Assert(IsFinite(value), "IEEE-754 +Inf, -Inf and NaN should be filtered out before calling this method."); Debug.Assert(value != 0, "IEEE-754 zero values should be handled by ZeroCount."); Debug.Assert(value > 0, "IEEE-754 negative values should be normalized before calling this method."); @@ -266,6 +266,16 @@ public int MapToIndex(double value) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsFinite(double value) + { +#if NET + return double.IsFinite(value); +#else + return !double.IsInfinity(value) && !double.IsNaN(value); +#endif + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LeadingZero64(long value) { From ea731b6d555f446c001d4ce6c023386355d488dc Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 18:08:49 +0200 Subject: [PATCH 11/19] FB --- src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs | 4 ---- .../tests/System.Collections.Immutable.Tests.csproj | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs b/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs index acaa2316746328..1bf701f7ee221d 100644 --- a/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#if !NET - using System.Runtime.CompilerServices; namespace System.Numerics @@ -13,5 +11,3 @@ internal static class BitOperations public static uint RotateLeft(uint value, int offset) => (value << offset) | (value >> (32 - offset)); } } - -#endif diff --git a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj index 2ebee16aa5df48..9325b03b5f2cc4 100644 --- a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj +++ b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj @@ -19,8 +19,8 @@ - - + + From 922b086c53f06dbd150f03b48d5cd5bdf82797f2 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 30 Mar 2026 18:09:16 +0200 Subject: [PATCH 12/19] Update src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs Co-authored-by: Jan Kotas --- src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs index 58d03c31250e61..ca9559db44f3ea 100644 --- a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs @@ -8,7 +8,6 @@ namespace System.Collections.Generic /// Provides downlevel polyfills for . internal static class KeyValuePairPolyfills { - [EditorBrowsable(EditorBrowsableState.Never)] public static void Deconstruct(this KeyValuePair source, out TKey key, out TValue value) { key = source.Key; From aaabccd8ee6ff7321100d8858201cd753c3ac41d Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 18:39:56 +0200 Subject: [PATCH 13/19] Address review feedback: fix usings, remove dead DictionaryPolyfills - StopwatchPolyfills.cs: add missing 'using System' for TimeSpan - RuntimeHelpersPolyfills.cs: add missing 'using System' for Type - CollectionsPolyfills.cs: remove unused 'using System.ComponentModel' - Delete DictionaryPolyfills.cs: unreferenced dead code, duplicates test DictionaryExtensions.cs, Queue polyfill misplaced (jkotas) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/Polyfills/CollectionsPolyfills.cs | 2 - .../src/Polyfills/DictionaryPolyfills.cs | 54 ------------------- .../src/Polyfills/RuntimeHelpersPolyfills.cs | 1 + .../src/Polyfills/StopwatchPolyfills.cs | 1 + 4 files changed, 2 insertions(+), 56 deletions(-) delete mode 100644 src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs diff --git a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs index ca9559db44f3ea..04f9f3e102c736 100644 --- a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.ComponentModel; - namespace System.Collections.Generic { /// Provides downlevel polyfills for . diff --git a/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs deleted file mode 100644 index ae512bac84f2b4..00000000000000 --- a/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics.CodeAnalysis; - -namespace System.Collections.Generic -{ - /// Provides downlevel polyfills for instance methods on dictionary types. - internal static class DictionaryPolyfills - { - extension(Dictionary dictionary) where TKey : notnull - { - public bool TryAdd(TKey key, TValue value) - { - if (!dictionary.ContainsKey(key)) - { - dictionary[key] = value; - return true; - } - - return false; - } - } - - extension(IDictionary dictionary) where TKey : notnull - { - public bool TryAdd(TKey key, TValue value) - { - if (!dictionary.ContainsKey(key)) - { - dictionary[key] = value; - return true; - } - - return false; - } - } - - extension(Queue queue) - { - public bool TryDequeue([NotNullWhen(true)] out T? result) - { - if (queue.Count > 0) - { - result = queue.Dequeue(); - return true; - } - - result = default; - return false; - } - } - } -} diff --git a/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs b/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs index 04aa1f421d4776..b8b1a137fef019 100644 --- a/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Runtime.CompilerServices; namespace System.Runtime.CompilerServices diff --git a/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs b/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs index a70cdc2767e931..1a0413d134cbfb 100644 --- a/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Diagnostics; namespace System.Diagnostics From 87571d48cd8fbfe47f1724d603827606a969ff67 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 18:52:34 +0200 Subject: [PATCH 14/19] Move DictionaryExtensions.cs to Common/src/Polyfills/DictionaryPolyfills.cs Per jkotas feedback: move the TryAdd polyfill from Common/tests/ to Common/src/Polyfills/ so it lives alongside other polyfills. Update all 5 test projects that referenced the old file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Polyfills/DictionaryPolyfills.cs} | 9 +++++---- src/libraries/Common/tests/Common.Tests.csproj | 4 ++-- .../tests/System.Collections.Immutable.Tests.csproj | 2 +- .../tests/System.Linq.Expressions.Tests.csproj | 4 ++-- .../System.Xml.Linq.TreeManipulation.Tests.csproj | 4 ++-- .../System.Xml.Linq.xNodeBuilder.Tests.csproj | 4 ++-- 6 files changed, 14 insertions(+), 13 deletions(-) rename src/libraries/Common/{tests/System/Collections/DictionaryExtensions.cs => src/Polyfills/DictionaryPolyfills.cs} (53%) diff --git a/src/libraries/Common/tests/System/Collections/DictionaryExtensions.cs b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs similarity index 53% rename from src/libraries/Common/tests/System/Collections/DictionaryExtensions.cs rename to src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs index a8cc9b4198fa33..8199afde039933 100644 --- a/src/libraries/Common/tests/System/Collections/DictionaryExtensions.cs +++ b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs @@ -3,13 +3,14 @@ namespace System.Collections.Generic { - internal static class DictionaryExtensions + /// Provides downlevel polyfills for instance methods on . + internal static class DictionaryPolyfills { - public static bool TryAdd(this IDictionary dict, TKey key, TValue value) + public static bool TryAdd(this IDictionary dictionary, TKey key, TValue value) { - if (!dict.ContainsKey(key)) + if (!dictionary.ContainsKey(key)) { - dict.Add(key, value); + dictionary.Add(key, value); return true; } diff --git a/src/libraries/Common/tests/Common.Tests.csproj b/src/libraries/Common/tests/Common.Tests.csproj index b665728750cc4b..dd184b098635f5 100644 --- a/src/libraries/Common/tests/Common.Tests.csproj +++ b/src/libraries/Common/tests/Common.Tests.csproj @@ -6,8 +6,8 @@ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-osx - + - + diff --git a/src/libraries/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj b/src/libraries/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj index 97ead77d068104..1352ecdfbcd1a6 100644 --- a/src/libraries/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj +++ b/src/libraries/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj @@ -223,8 +223,8 @@ - + diff --git a/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/System.Xml.Linq.TreeManipulation.Tests.csproj b/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/System.Xml.Linq.TreeManipulation.Tests.csproj index ea539d2f80c484..1805fc4dd3f194 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/System.Xml.Linq.TreeManipulation.Tests.csproj +++ b/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/System.Xml.Linq.TreeManipulation.Tests.csproj @@ -3,8 +3,8 @@ $(NetCoreAppCurrent) - + diff --git a/src/libraries/System.Private.Xml.Linq/tests/xNodeBuilder/System.Xml.Linq.xNodeBuilder.Tests.csproj b/src/libraries/System.Private.Xml.Linq/tests/xNodeBuilder/System.Xml.Linq.xNodeBuilder.Tests.csproj index 2f28c03a4f266d..65a781aa853eea 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/xNodeBuilder/System.Xml.Linq.xNodeBuilder.Tests.csproj +++ b/src/libraries/System.Private.Xml.Linq/tests/xNodeBuilder/System.Xml.Linq.xNodeBuilder.Tests.csproj @@ -4,8 +4,8 @@ $(NetCoreAppCurrent) - + From 8afd56b637e3a32ce7b89ab8d6e45395495fd0e6 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 30 Mar 2026 23:38:59 +0200 Subject: [PATCH 15/19] Use file-scoped namespaces in Polyfills; unrevert DiagnosticSource polyfill Convert all src/libraries/Common/src/Polyfills/*.cs to file-scoped namespace declarations. Restore DoublePolyfills usage in Base2ExponentialHistogramAggregator (revert the revert). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Common/src/Polyfills/ArrayPolyfills.cs | 15 ++++--- .../Common/src/Polyfills/BitArrayPolyfills.cs | 25 ++++++----- .../src/Polyfills/BitConverterPolyfills.cs | 29 +++++++------ .../src/Polyfills/BitOperationsPolyfills.cs | 13 +++--- .../src/Polyfills/CollectionsPolyfills.cs | 17 ++++---- .../src/Polyfills/DateTimeOffsetPolyfills.cs | 17 ++++---- .../src/Polyfills/DictionaryPolyfills.cs | 23 +++++------ .../Common/src/Polyfills/DoublePolyfills.cs | 21 +++++----- .../src/Polyfills/EnvironmentPolyfills.cs | 21 +++++----- .../Common/src/Polyfills/GuidPolyfills.cs | 41 +++++++++---------- .../Common/src/Polyfills/HashCodePolyfills.cs | 27 ++++++------ .../src/Polyfills/RuntimeHelpersPolyfills.cs | 37 ++++++++--------- .../Common/src/Polyfills/SinglePolyfills.cs | 21 +++++----- .../src/Polyfills/StopwatchPolyfills.cs | 25 ++++++----- .../Common/src/Polyfills/StreamPolyfills.cs | 35 ++++++++-------- .../src/Polyfills/TextWriterPolyfills.cs | 17 ++++---- ...System.Diagnostics.DiagnosticSource.csproj | 1 + .../Base2ExponentialHistogramAggregator.cs | 14 +------ 18 files changed, 187 insertions(+), 212 deletions(-) diff --git a/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs b/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs index 53fe041627093b..3332e2b97dc2d3 100644 --- a/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs @@ -1,14 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System +namespace System; + +/// Provides downlevel polyfills for static members on . +internal static class ArrayPolyfills { - /// Provides downlevel polyfills for static members on . - internal static class ArrayPolyfills + extension(Array) { - extension(Array) - { - public static int MaxLength => 0x7FFFFFC7; - } + public static int MaxLength => 0x7FFFFFC7; } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs b/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs index 5d84c4e938e437..19f573647ef79e 100644 --- a/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs @@ -3,25 +3,24 @@ using System.Collections; -namespace System.Collections +namespace System.Collections; + +/// Provides downlevel polyfills for instance methods on . +internal static class BitArrayPolyfills { - /// Provides downlevel polyfills for instance methods on . - internal static class BitArrayPolyfills + extension(BitArray bitArray) { - extension(BitArray bitArray) + public bool HasAllSet() { - public bool HasAllSet() + for (int i = 0; i < bitArray.Count; i++) { - for (int i = 0; i < bitArray.Count; i++) + if (!bitArray[i]) { - if (!bitArray[i]) - { - return false; - } + return false; } - - return true; } + + return true; } } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs b/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs index e597f17c02a2f2..212cfd50d25a17 100644 --- a/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs @@ -1,28 +1,27 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System +namespace System; + +/// Provides downlevel polyfills for static methods on . +internal static class BitConverterPolyfills { - /// Provides downlevel polyfills for static methods on . - internal static class BitConverterPolyfills + extension(BitConverter) { - extension(BitConverter) + public static uint SingleToUInt32Bits(float value) { - public static uint SingleToUInt32Bits(float value) + unsafe { - unsafe - { - return *(uint*)&value; - } + return *(uint*)&value; } + } - public static ulong DoubleToUInt64Bits(double value) + public static ulong DoubleToUInt64Bits(double value) + { + unsafe { - unsafe - { - return *(ulong*)&value; - } + return *(ulong*)&value; } } } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs b/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs index 1bf701f7ee221d..656d2150e86680 100644 --- a/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs @@ -3,11 +3,10 @@ using System.Runtime.CompilerServices; -namespace System.Numerics +namespace System.Numerics; + +internal static class BitOperations { - internal static class BitOperations - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint RotateLeft(uint value, int offset) => (value << offset) | (value >> (32 - offset)); - } -} + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) => (value << offset) | (value >> (32 - offset)); +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs index 04f9f3e102c736..debdceddacf0b9 100644 --- a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs @@ -1,15 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Collections.Generic +namespace System.Collections.Generic; + +/// Provides downlevel polyfills for . +internal static class KeyValuePairPolyfills { - /// Provides downlevel polyfills for . - internal static class KeyValuePairPolyfills + public static void Deconstruct(this KeyValuePair source, out TKey key, out TValue value) { - public static void Deconstruct(this KeyValuePair source, out TKey key, out TValue value) - { - key = source.Key; - value = source.Value; - } + key = source.Key; + value = source.Value; } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs b/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs index 335cfa6f94b016..2dd56916e8c697 100644 --- a/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs @@ -1,15 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System +namespace System; + +/// Provides downlevel polyfills for instance members on . +internal static class DateTimeOffsetPolyfills { - /// Provides downlevel polyfills for instance members on . - internal static class DateTimeOffsetPolyfills + extension(DateTimeOffset value) { - extension(DateTimeOffset value) - { - public int TotalOffsetMinutes => - (int)(value.Offset.Ticks / TimeSpan.TicksPerMinute); - } + public int TotalOffsetMinutes => + (int)(value.Offset.Ticks / TimeSpan.TicksPerMinute); } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs index 8199afde039933..05fa6f3136291d 100644 --- a/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs @@ -1,20 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Collections.Generic +namespace System.Collections.Generic; + +/// Provides downlevel polyfills for instance methods on . +internal static class DictionaryPolyfills { - /// Provides downlevel polyfills for instance methods on . - internal static class DictionaryPolyfills + public static bool TryAdd(this IDictionary dictionary, TKey key, TValue value) { - public static bool TryAdd(this IDictionary dictionary, TKey key, TValue value) + if (!dictionary.ContainsKey(key)) { - if (!dictionary.ContainsKey(key)) - { - dictionary.Add(key, value); - return true; - } - - return false; + dictionary.Add(key, value); + return true; } + + return false; } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/DoublePolyfills.cs b/src/libraries/Common/src/Polyfills/DoublePolyfills.cs index 86d2444f6994fd..60e16390ea34f7 100644 --- a/src/libraries/Common/src/Polyfills/DoublePolyfills.cs +++ b/src/libraries/Common/src/Polyfills/DoublePolyfills.cs @@ -3,19 +3,18 @@ using System.Runtime.CompilerServices; -namespace System +namespace System; + +/// Provides downlevel polyfills for static methods on . +internal static class DoublePolyfills { - /// Provides downlevel polyfills for static methods on . - internal static class DoublePolyfills + extension(double) { - extension(double) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsFinite(double d) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsFinite(double d) - { - long bits = BitConverter.DoubleToInt64Bits(d); - return ((ulong)~bits & 0x7FF0_0000_0000_0000UL) != 0; - } + long bits = BitConverter.DoubleToInt64Bits(d); + return ((ulong)~bits & 0x7FF0_0000_0000_0000UL) != 0; } } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs b/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs index e32970b4e462c0..c5925945b3151c 100644 --- a/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs @@ -3,21 +3,20 @@ using System.Diagnostics; -namespace System +namespace System; + +/// Provides downlevel polyfills for static members on . +internal static class EnvironmentPolyfills { - /// Provides downlevel polyfills for static members on . - internal static class EnvironmentPolyfills + extension(Environment) { - extension(Environment) + public static int ProcessId { - public static int ProcessId + get { - get - { - using Process currentProcess = Process.GetCurrentProcess(); - return currentProcess.Id; - } + using Process currentProcess = Process.GetCurrentProcess(); + return currentProcess.Id; } } } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/GuidPolyfills.cs b/src/libraries/Common/src/Polyfills/GuidPolyfills.cs index 7304b2dbc33155..5bc96108432e42 100644 --- a/src/libraries/Common/src/Polyfills/GuidPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/GuidPolyfills.cs @@ -4,31 +4,30 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace System +namespace System; + +/// Provides downlevel polyfills for instance methods on . +internal static class GuidPolyfills { - /// Provides downlevel polyfills for instance methods on . - internal static class GuidPolyfills + extension(Guid self) { - extension(Guid self) + public bool TryWriteBytes(Span destination) { - public bool TryWriteBytes(Span destination) - { - if (destination.Length < 16) - return false; + if (destination.Length < 16) + return false; - ref Guid selfRef = ref Unsafe.AsRef(in self); - if (BitConverter.IsLittleEndian) - { - MemoryMarshal.Write(destination, ref selfRef); - } - else - { - // slower path for BigEndian - self.ToByteArray().AsSpan().CopyTo(destination); - } - - return true; + ref Guid selfRef = ref Unsafe.AsRef(in self); + if (BitConverter.IsLittleEndian) + { + MemoryMarshal.Write(destination, ref selfRef); } + else + { + // slower path for BigEndian + self.ToByteArray().AsSpan().CopyTo(destination); + } + + return true; } } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs b/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs index ff2f0d2beed601..d6bb323ea3c4d2 100644 --- a/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs +++ b/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs @@ -3,23 +3,22 @@ using System.Runtime.InteropServices; -namespace System +namespace System; + +/// Provides downlevel polyfills for instance methods on . +internal static class HashCodePolyfills { - /// Provides downlevel polyfills for instance methods on . - internal static class HashCodePolyfills + public static void AddBytes(this ref HashCode hashCode, ReadOnlySpan value) { - public static void AddBytes(this ref HashCode hashCode, ReadOnlySpan value) + while (value.Length >= sizeof(int)) { - while (value.Length >= sizeof(int)) - { - hashCode.Add(MemoryMarshal.Read(value)); - value = value.Slice(sizeof(int)); - } + hashCode.Add(MemoryMarshal.Read(value)); + value = value.Slice(sizeof(int)); + } - foreach (byte b in value) - { - hashCode.Add(b); - } + foreach (byte b in value) + { + hashCode.Add(b); } } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs b/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs index b8b1a137fef019..003dbc0c720417 100644 --- a/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs @@ -4,32 +4,31 @@ using System; using System.Runtime.CompilerServices; -namespace System.Runtime.CompilerServices +namespace System.Runtime.CompilerServices; + +/// Provides downlevel polyfills for static methods on . +internal static class RuntimeHelpersPolyfills { - /// Provides downlevel polyfills for static methods on . - internal static class RuntimeHelpersPolyfills + extension(RuntimeHelpers) { - extension(RuntimeHelpers) + public static bool TryEnsureSufficientExecutionStack() { - public static bool TryEnsureSufficientExecutionStack() + try { - try - { - RuntimeHelpers.EnsureSufficientExecutionStack(); - return true; - } - catch - { - return false; - } + RuntimeHelpers.EnsureSufficientExecutionStack(); + return true; } - - public static object GetUninitializedObject(Type type) + catch { + return false; + } + } + + public static object GetUninitializedObject(Type type) + { #pragma warning disable SYSLIB0050 // FormatterServices.GetUninitializedObject is obsolete - return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); + return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); #pragma warning restore SYSLIB0050 - } } } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/SinglePolyfills.cs b/src/libraries/Common/src/Polyfills/SinglePolyfills.cs index b2af28b3bbd60e..cd2c804492fbc3 100644 --- a/src/libraries/Common/src/Polyfills/SinglePolyfills.cs +++ b/src/libraries/Common/src/Polyfills/SinglePolyfills.cs @@ -3,19 +3,18 @@ using System.Runtime.CompilerServices; -namespace System +namespace System; + +/// Provides downlevel polyfills for static methods on . +internal static class SinglePolyfills { - /// Provides downlevel polyfills for static methods on . - internal static class SinglePolyfills + extension(float) { - extension(float) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool IsFinite(float f) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe bool IsFinite(float f) - { - uint bits = *(uint*)&f; - return (~bits & 0x7F80_0000U) != 0; - } + uint bits = *(uint*)&f; + return (~bits & 0x7F80_0000U) != 0; } } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs b/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs index 1a0413d134cbfb..e6be6f9df97254 100644 --- a/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs @@ -4,20 +4,19 @@ using System; using System.Diagnostics; -namespace System.Diagnostics +namespace System.Diagnostics; + +/// Provides downlevel polyfills for static methods on . +internal static class StopwatchPolyfills { - /// Provides downlevel polyfills for static methods on . - internal static class StopwatchPolyfills - { - private static readonly double s_tickFrequency = (double)TimeSpan.TicksPerSecond / Stopwatch.Frequency; + private static readonly double s_tickFrequency = (double)TimeSpan.TicksPerSecond / Stopwatch.Frequency; - extension(Stopwatch) - { - public static TimeSpan GetElapsedTime(long startingTimestamp) => - new((long)((Stopwatch.GetTimestamp() - startingTimestamp) * s_tickFrequency)); + extension(Stopwatch) + { + public static TimeSpan GetElapsedTime(long startingTimestamp) => + new((long)((Stopwatch.GetTimestamp() - startingTimestamp) * s_tickFrequency)); - public static TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp) => - new((long)((endingTimestamp - startingTimestamp) * s_tickFrequency)); - } + public static TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp) => + new((long)((endingTimestamp - startingTimestamp) * s_tickFrequency)); } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/StreamPolyfills.cs b/src/libraries/Common/src/Polyfills/StreamPolyfills.cs index 4e918b8de54f86..923b1accccc2c8 100644 --- a/src/libraries/Common/src/Polyfills/StreamPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/StreamPolyfills.cs @@ -4,30 +4,29 @@ using System.Threading; using System.Threading.Tasks; -namespace System.IO +namespace System.IO; + +/// Provides downlevel polyfills for instance methods on . +internal static class StreamPolyfills { - /// Provides downlevel polyfills for instance methods on . - internal static class StreamPolyfills + extension(Stream stream) { - extension(Stream stream) + public void ReadExactly(byte[] buffer) { - public void ReadExactly(byte[] buffer) + int totalRead = 0; + while (totalRead < buffer.Length) { - int totalRead = 0; - while (totalRead < buffer.Length) + int read = stream.Read(buffer, totalRead, buffer.Length - totalRead); + if (read == 0) { - int read = stream.Read(buffer, totalRead, buffer.Length - totalRead); - if (read == 0) - { - throw new EndOfStreamException(); - } - - totalRead += read; + throw new EndOfStreamException(); } - } - public Task CopyToAsync(Stream destination, CancellationToken cancellationToken) => - stream.CopyToAsync(destination, 81_920, cancellationToken); // 81_920 is the default buffer size used by Stream.CopyToAsync on .NET + totalRead += read; + } } + + public Task CopyToAsync(Stream destination, CancellationToken cancellationToken) => + stream.CopyToAsync(destination, 81_920, cancellationToken); // 81_920 is the default buffer size used by Stream.CopyToAsync on .NET } -} +} \ No newline at end of file diff --git a/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs b/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs index fe26446fe4c128..fc2832925541c2 100644 --- a/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs @@ -1,15 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.IO +namespace System.IO; + +/// Provides downlevel polyfills for instance methods on . +internal static class TextWriterPolyfills { - /// Provides downlevel polyfills for instance methods on . - internal static class TextWriterPolyfills + extension(TextWriter writer) { - extension(TextWriter writer) - { - public void Write(ReadOnlySpan value) => - writer.Write(value.ToString()); - } + public void Write(ReadOnlySpan value) => + writer.Write(value.ToString()); } -} +} \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index a18b479fcea19c..ecdb05dc3eb4ff 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -132,6 +132,7 @@ System.Diagnostics.DiagnosticSource + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs index 09043dd5b0df6c..d162b767882e8f 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs @@ -172,7 +172,7 @@ public override IAggregationStatistics Collect() public override void Update(double measurement) { - if (!IsFinite(measurement)) + if (!double.IsFinite(measurement)) { return; } @@ -232,7 +232,7 @@ public override void Update(double measurement) /// Returns the index of the bucket. public int MapToIndex(double value) { - Debug.Assert(IsFinite(value), "IEEE-754 +Inf, -Inf and NaN should be filtered out before calling this method."); + Debug.Assert(double.IsFinite(value), "IEEE-754 +Inf, -Inf and NaN should be filtered out before calling this method."); Debug.Assert(value != 0, "IEEE-754 zero values should be handled by ZeroCount."); Debug.Assert(value > 0, "IEEE-754 negative values should be normalized before calling this method."); @@ -266,16 +266,6 @@ public int MapToIndex(double value) } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsFinite(double value) - { -#if NET - return double.IsFinite(value); -#else - return !double.IsInfinity(value) && !double.IsNaN(value); -#endif - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LeadingZero64(long value) { From 87710180e80bde863ef2ac5720a213a156bba414 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 31 Mar 2026 13:17:27 +0200 Subject: [PATCH 16/19] Fix SA1518: add trailing newline to all Polyfills files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/libraries/Common/src/Polyfills/ArrayPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/DoublePolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/GuidPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/HashCodePolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/SinglePolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/StreamPolyfills.cs | 2 +- src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs b/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs index 3332e2b97dc2d3..c1b563bc84d9d9 100644 --- a/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/ArrayPolyfills.cs @@ -10,4 +10,4 @@ internal static class ArrayPolyfills { public static int MaxLength => 0x7FFFFFC7; } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs b/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs index 19f573647ef79e..430aeaec2eece6 100644 --- a/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs @@ -23,4 +23,4 @@ public bool HasAllSet() return true; } } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs b/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs index 212cfd50d25a17..dd418d32f94406 100644 --- a/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs @@ -24,4 +24,4 @@ public static ulong DoubleToUInt64Bits(double value) } } } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs b/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs index 656d2150e86680..780abeb26d2add 100644 --- a/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/BitOperationsPolyfills.cs @@ -9,4 +9,4 @@ internal static class BitOperations { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint RotateLeft(uint value, int offset) => (value << offset) | (value >> (32 - offset)); -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs index debdceddacf0b9..414ad64bcf8d0b 100644 --- a/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs @@ -11,4 +11,4 @@ public static void Deconstruct(this KeyValuePair sou key = source.Key; value = source.Value; } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs b/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs index 2dd56916e8c697..1dcbae615775ad 100644 --- a/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs @@ -11,4 +11,4 @@ internal static class DateTimeOffsetPolyfills public int TotalOffsetMinutes => (int)(value.Offset.Ticks / TimeSpan.TicksPerMinute); } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs index 05fa6f3136291d..a6c1e9bce2b5c1 100644 --- a/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs @@ -16,4 +16,4 @@ public static bool TryAdd(this IDictionary dictionar return false; } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/DoublePolyfills.cs b/src/libraries/Common/src/Polyfills/DoublePolyfills.cs index 60e16390ea34f7..b469f1d17d8fc2 100644 --- a/src/libraries/Common/src/Polyfills/DoublePolyfills.cs +++ b/src/libraries/Common/src/Polyfills/DoublePolyfills.cs @@ -17,4 +17,4 @@ public static bool IsFinite(double d) return ((ulong)~bits & 0x7FF0_0000_0000_0000UL) != 0; } } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs b/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs index c5925945b3151c..acb081bf51592f 100644 --- a/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs @@ -19,4 +19,4 @@ public static int ProcessId } } } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/GuidPolyfills.cs b/src/libraries/Common/src/Polyfills/GuidPolyfills.cs index 5bc96108432e42..8614e6f796d4c5 100644 --- a/src/libraries/Common/src/Polyfills/GuidPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/GuidPolyfills.cs @@ -30,4 +30,4 @@ public bool TryWriteBytes(Span destination) return true; } } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs b/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs index d6bb323ea3c4d2..7b2bc309c24bfd 100644 --- a/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs +++ b/src/libraries/Common/src/Polyfills/HashCodePolyfills.cs @@ -21,4 +21,4 @@ public static void AddBytes(this ref HashCode hashCode, ReadOnlySpan value hashCode.Add(b); } } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs b/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs index 003dbc0c720417..0f60f78e1287d7 100644 --- a/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/RuntimeHelpersPolyfills.cs @@ -31,4 +31,4 @@ public static object GetUninitializedObject(Type type) #pragma warning restore SYSLIB0050 } } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/SinglePolyfills.cs b/src/libraries/Common/src/Polyfills/SinglePolyfills.cs index cd2c804492fbc3..a654095a13e732 100644 --- a/src/libraries/Common/src/Polyfills/SinglePolyfills.cs +++ b/src/libraries/Common/src/Polyfills/SinglePolyfills.cs @@ -17,4 +17,4 @@ public static unsafe bool IsFinite(float f) return (~bits & 0x7F80_0000U) != 0; } } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs b/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs index e6be6f9df97254..1608d36e9170e4 100644 --- a/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs @@ -19,4 +19,4 @@ public static TimeSpan GetElapsedTime(long startingTimestamp) => public static TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp) => new((long)((endingTimestamp - startingTimestamp) * s_tickFrequency)); } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/StreamPolyfills.cs b/src/libraries/Common/src/Polyfills/StreamPolyfills.cs index 923b1accccc2c8..076f7faa5676ea 100644 --- a/src/libraries/Common/src/Polyfills/StreamPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/StreamPolyfills.cs @@ -29,4 +29,4 @@ public void ReadExactly(byte[] buffer) public Task CopyToAsync(Stream destination, CancellationToken cancellationToken) => stream.CopyToAsync(destination, 81_920, cancellationToken); // 81_920 is the default buffer size used by Stream.CopyToAsync on .NET } -} \ No newline at end of file +} diff --git a/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs b/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs index fc2832925541c2..cff559d3ca617d 100644 --- a/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs +++ b/src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs @@ -11,4 +11,4 @@ internal static class TextWriterPolyfills public void Write(ReadOnlySpan value) => writer.Write(value.ToString()); } -} \ No newline at end of file +} From 721b99fa442826d3bc925b5312e558482868c4b3 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 31 Mar 2026 14:52:29 +0200 Subject: [PATCH 17/19] Fix net481 CI: add DoublePolyfills to DiagnosticSource test project The test project directly compiles Base2ExponentialHistogramAggregator.cs from ../src/ but didn't include DoublePolyfills.cs, causing CS0117 'double does not contain a definition for IsFinite' on net481. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../tests/System.Diagnostics.DiagnosticSource.Tests.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index 1b3172278e278c..f96ce52f55badd 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -75,4 +75,8 @@ + + + + From 0f641576892d6ada44f2aa6d6780e4f9b4490810 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:27:43 +0000 Subject: [PATCH 18/19] Move EncodingPolyfills.cs to Common/src/Polyfills/ directory Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06841447-52ae-4051-badf-068f74c098a8 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../Common/src/Polyfills/EncodingPolyfills.cs | 81 ++++++++++++++++++ .../src/System/Text/EncodingPolyfills.cs | 82 ------------------- src/libraries/Directory.Build.targets | 2 +- ...icrosoft.Extensions.Logging.Console.csproj | 2 +- 4 files changed, 83 insertions(+), 84 deletions(-) create mode 100644 src/libraries/Common/src/Polyfills/EncodingPolyfills.cs delete mode 100644 src/libraries/Common/src/System/Text/EncodingPolyfills.cs diff --git a/src/libraries/Common/src/Polyfills/EncodingPolyfills.cs b/src/libraries/Common/src/Polyfills/EncodingPolyfills.cs new file mode 100644 index 00000000000000..6bfe09449f0508 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/EncodingPolyfills.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Text; + +/// Provides downlevel polyfills for span-based Encoding APIs. +internal static class EncodingPolyfills +{ + public static unsafe int GetByteCount(this Encoding encoding, ReadOnlySpan chars) + { + fixed (char* charsPtr = &GetNonNullPinnableReference(chars)) + { + return encoding.GetByteCount(charsPtr, chars.Length); + } + } + + public static unsafe int GetCharCount(this Encoding encoding, ReadOnlySpan bytes) + { + fixed (byte* bytesPtr = &GetNonNullPinnableReference(bytes)) + { + return encoding.GetCharCount(bytesPtr, bytes.Length); + } + } + + public static int GetBytes(this Encoding encoding, string str, Span bytes) + { + return GetBytes(encoding, str.AsSpan(), bytes); + } + + public static unsafe int GetBytes(this Encoding encoding, ReadOnlySpan chars, Span bytes) + { + fixed (char* charsPtr = &GetNonNullPinnableReference(chars)) + fixed (byte* bytesPtr = &GetNonNullPinnableReference(bytes)) + { + return encoding.GetBytes(charsPtr, chars.Length, bytesPtr, bytes.Length); + } + } + + public static unsafe int GetChars(this Encoding encoding, ReadOnlySpan bytes, Span chars) + { + fixed (byte* bytesPtr = &GetNonNullPinnableReference(bytes)) + fixed (char* charsPtr = &GetNonNullPinnableReference(chars)) + { + return encoding.GetChars(bytesPtr, bytes.Length, charsPtr, chars.Length); + } + } + + public static unsafe string GetString(this Encoding encoding, ReadOnlySpan bytes) + { + fixed (byte* bytesPtr = &GetNonNullPinnableReference(bytes)) + { + return encoding.GetString(bytesPtr, bytes.Length); + } + } + + public static bool TryGetChars(this Encoding encoding, ReadOnlySpan bytes, Span chars, out int charsWritten) + { + int charCount = encoding.GetCharCount(bytes); + + if (charCount > chars.Length) + { + charsWritten = 0; + return false; + } + + charsWritten = encoding.GetChars(bytes, chars); + Debug.Assert(charCount == charsWritten); + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe ref readonly T GetNonNullPinnableReference(ReadOnlySpan buffer) + { + // Based on the internal implementation from MemoryMarshal. + return ref buffer.Length != 0 ? ref MemoryMarshal.GetReference(buffer) : ref Unsafe.AsRef((void*)1); + } +} diff --git a/src/libraries/Common/src/System/Text/EncodingPolyfills.cs b/src/libraries/Common/src/System/Text/EncodingPolyfills.cs deleted file mode 100644 index 9e2981db8f922d..00000000000000 --- a/src/libraries/Common/src/System/Text/EncodingPolyfills.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace System.Text -{ - /// Provides downlevel polyfills for span-based Encoding APIs. - internal static class EncodingPolyfills - { - public static unsafe int GetByteCount(this Encoding encoding, ReadOnlySpan chars) - { - fixed (char* charsPtr = &GetNonNullPinnableReference(chars)) - { - return encoding.GetByteCount(charsPtr, chars.Length); - } - } - - public static unsafe int GetCharCount(this Encoding encoding, ReadOnlySpan bytes) - { - fixed (byte* bytesPtr = &GetNonNullPinnableReference(bytes)) - { - return encoding.GetCharCount(bytesPtr, bytes.Length); - } - } - - public static int GetBytes(this Encoding encoding, string str, Span bytes) - { - return GetBytes(encoding, str.AsSpan(), bytes); - } - - public static unsafe int GetBytes(this Encoding encoding, ReadOnlySpan chars, Span bytes) - { - fixed (char* charsPtr = &GetNonNullPinnableReference(chars)) - fixed (byte* bytesPtr = &GetNonNullPinnableReference(bytes)) - { - return encoding.GetBytes(charsPtr, chars.Length, bytesPtr, bytes.Length); - } - } - - public static unsafe int GetChars(this Encoding encoding, ReadOnlySpan bytes, Span chars) - { - fixed (byte* bytesPtr = &GetNonNullPinnableReference(bytes)) - fixed (char* charsPtr = &GetNonNullPinnableReference(chars)) - { - return encoding.GetChars(bytesPtr, bytes.Length, charsPtr, chars.Length); - } - } - - public static unsafe string GetString(this Encoding encoding, ReadOnlySpan bytes) - { - fixed (byte* bytesPtr = &GetNonNullPinnableReference(bytes)) - { - return encoding.GetString(bytesPtr, bytes.Length); - } - } - - public static bool TryGetChars(this Encoding encoding, ReadOnlySpan bytes, Span chars, out int charsWritten) - { - int charCount = encoding.GetCharCount(bytes); - - if (charCount > chars.Length) - { - charsWritten = 0; - return false; - } - - charsWritten = encoding.GetChars(bytes, chars); - Debug.Assert(charCount == charsWritten); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe ref readonly T GetNonNullPinnableReference(ReadOnlySpan buffer) - { - // Based on the internal implementation from MemoryMarshal. - return ref buffer.Length != 0 ? ref MemoryMarshal.GetReference(buffer) : ref Unsafe.AsRef((void*)1); - } - } -} diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index c1f238a86bd203..b6fee26af35e3d 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -208,7 +208,7 @@ - +