Skip to content

Replace string.Compare == 0 patterns with Equals/StartsWith/AsSpan calls#124566

Open
Copilot wants to merge 7 commits intomainfrom
copilot/refactor-string-comparison-logic
Open

Replace string.Compare == 0 patterns with Equals/StartsWith/AsSpan calls#124566
Copilot wants to merge 7 commits intomainfrom
copilot/refactor-string-comparison-logic

Conversation

Copy link
Contributor

Copilot AI commented Feb 18, 2026

  • Replace string.Compare(...) == 0 / != 0 patterns with Equals/StartsWith/EndsWith/AsSpan across source files
  • ManagementQuery.cs (~32 occurrences) - all StartsWith replacements
  • Networking files: CredentialCacheKey, HttpListener, HttpListenerContext, HttpListener.Windows, SmtpConnection.Auth, HttpWindowsProxy, WebProxy, AuthenticationHeaderValue
  • CoreLib files: SecurityElement, HijriCalendar, IdnMapping, Environment.GetFolderPathCore.Unix
  • Configuration files: StringUtil, UrlPath, AppSettingsReader
  • Data files: DataTable (EndsWith for ASC/DESC), OdbcUtils
  • XML files: XdrBuilder, XHashtable, XNamespace, XsltFunctions, StringFunctions
  • Serialization: EnumDataContract
  • ComponentModel: DesignerOptionService, ReflectPropertyDescriptor, ComponentResourceManager
  • DirectoryServices: Utils.cs (3 occurrences)
  • Mono: RuntimeModuleBuilder.Mono.cs (InvariantCultureIgnoreCase)
  • CoreCLR tools: dotnet-pgo/Program.cs, EcmaModule.Sorting.cs, AssemblyQualifiedToken
  • Caching: FileChangeNotificationSystem
  • EventLog: EventLog.cs
  • Address review feedback round 1 (null checks, simplify patterns, remove redundant length checks)
  • Address review feedback round 2 (IdnMapping length check, FileChangeNotificationSystem instance Equals)

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits February 18, 2026 19:24
Replace all instances of the verbose pattern:
  (q.Length >= keyword.Length) && (string.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase) == 0)
and its != 0 / 0 != variants with the simpler:
  q.StartsWith(keyword, StringComparison.OrdinalIgnoreCase)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace string.Compare == 0 / != 0 patterns with more idiomatic
Equals, StartsWith, and AsSpan alternatives across System.Net libraries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sWith/AsSpan in remaining source files

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor string comparison logic to use Equals method Replace string.Compare == 0 patterns with Equals/StartsWith/AsSpan calls Feb 18, 2026
Copilot AI requested a review from MihaZupan February 18, 2026 19:44
…ls(..., Ordinal)

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Copilot AI requested a review from EgorBo February 18, 2026 20:34
Copy link
Member

@MihaZupan MihaZupan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Address all comments. For any suggestions that point at more patterns that can be switched, look for more places where they could apply to

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-meta
See info in area-owners.md if you want to be subscribed.

…dant length checks

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 18, 2026

@copilot Address all comments. For any suggestions that point at more patterns that can be switched, look for more places where they could apply to

All comments addressed in 9479aff: null safety fixes in StringUtil and HijriCalendar, simplified ComponentResourceManager/DirectoryServices patterns, replaced the remaining string.Compare in SmtpConnection.Auth, and removed redundant length checks across 8 files (SecurityElement, EnumDataContract, XHashtable, XNamespace, XdrBuilder, StringFunctions, XsltFunctions, FileChangeNotificationSystem).

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 10c5e266c5a94725a1a9d128689c2308
    • Triggering command: /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet exec --runtimeconfig /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.deps.json /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/testhost.dll --port 38909 --endpoint 127.0.0.1:038909 --role client --parentprocessid 30451 --datacollectionport 41653 --telemetryoptedin false DTARGET_64BIT -D--others (dns block)
  • 5d0fddfa8dd54859a60706f04b1d4959
    • Triggering command: /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet exec --runtimeconfig /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.deps.json /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/testhost.dll --port 38909 --endpoint 127.0.0.1:038909 --role client --parentprocessid 30451 --datacollectionport 41653 --telemetryoptedin false DTARGET_64BIT -D--others (dns block)
  • 69ff98bbf1924634b93257023b62350c
    • Triggering command: /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet exec --runtimeconfig /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.deps.json /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/testhost.dll --port 38909 --endpoint 127.0.0.1:038909 --role client --parentprocessid 30451 --datacollectionport 41653 --telemetryoptedin false DTARGET_64BIT -D--others (dns block)
  • 7c833bcc974149418852f0abe1a379f5
    • Triggering command: /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet exec --runtimeconfig /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.deps.json /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/testhost.dll --port 38909 --endpoint 127.0.0.1:038909 --role client --parentprocessid 30451 --datacollectionport 41653 --telemetryoptedin false DTARGET_64BIT -D--others (dns block)
  • f435685089c74e0790afa87f227ebca2
    • Triggering command: /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet /home/REDACTED/work/runtime/runtime/artifacts/bin/testhost/net11.0-linux-Debug-x64/dotnet exec --runtimeconfig /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/System.Net.Mail.Functional.Tests.deps.json /home/REDACTED/work/runtime/runtime/artifacts/bin/System.Net.Mail.Functional.Tests/Debug/net11.0-unix/testhost.dll --port 38909 --endpoint 127.0.0.1:038909 --role client --parentprocessid 30451 --datacollectionport 41653 --telemetryoptedin false DTARGET_64BIT -D--others (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copy link
Member

@MihaZupan MihaZupan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Address the last comments

…n FileChangeNotificationSystem.cs

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copilot AI requested a review from MihaZupan February 18, 2026 22:47
@MihaZupan MihaZupan added this to the 11.0.0 milestone Feb 18, 2026
@MihaZupan MihaZupan marked this pull request as ready for review February 18, 2026 22:48
@MihaZupan MihaZupan requested a review from steveisok as a code owner February 18, 2026 22:48
Copilot AI review requested due to automatic review settings February 18, 2026 22:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request systematically replaces verbose string.Compare(...) == 0 / != 0 patterns with more idiomatic and performant alternatives across the codebase. The changes improve code readability and maintainability by using appropriate methods like Equals, StartsWith, EndsWith, and span-based comparisons.

Changes:

  • Replace equality checks using string.Compare(...) == 0 with string.Equals() or direct equality operators
  • Replace prefix checks using string.Compare(str, 0, prefix, 0, length) == 0 with StartsWith() or AsSpan().StartsWith()
  • Replace suffix checks with EndsWith() methods
  • Simplify substring comparisons using AsSpan().Equals() for better performance
  • Add appropriate null checks where needed (e.g., HijriCalendar, SmtpConnection, StringUtil)

Reviewed changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated no comments.

Show a summary per file
File Description
RuntimeModuleBuilder.Mono.cs Replace case-insensitive Compare with Equals using InvariantCultureIgnoreCase
FileChangeNotificationSystem.cs Simplify length check and comparison to single Equals call
XsltFunctions.cs Replace substring comparison with StartsWith for prefix checking
StringFunctions.cs Replace substring comparison with StartsWith for prefix checking
XdrBuilder.cs Replace substring comparison with StartsWith, remove redundant length check
XNamespace.cs Use AsSpan().Equals() for substring comparison with special namespace constants
XHashtable.cs Use AsSpan().Equals() for key comparison in hash table lookup
EnumDataContract.cs Use AsSpan().Equals() for enum member name matching
SecurityElement.cs Replace substring comparison with AsSpan().StartsWith() for escape sequence detection
IdnMapping.cs Replace ACE prefix check with AsSpan().StartsWith() (preserves short-circuit behavior)
HijriCalendar.Win32.cs Add null check and use StartsWith for registry key prefix matching
Environment.GetFolderPathCore.Unix.cs Replace substring comparisons with AsSpan().StartsWith() for XDG directory parsing
WebProxy.NonWasm.cs Replace substring comparison with AsSpan().Equals() for domain name matching
SmtpConnection.Auth.cs Add null check and replace multiple substring comparisons with StartsWith
HttpListener.Windows.cs Replace authentication header comparisons with AsSpan().Equals()
HttpListenerContext.Managed.cs Replace Basic auth header check with AsSpan().Equals()
HttpListener.cs Replace URL scheme checks with StartsWith for http:// and https://
HttpWindowsProxy.cs Replace proxy bypass string checks with AsSpan().StartsWith()
AuthenticationHeaderValue.cs Use AsSpan().Equals() for authentication scheme comparison
ManagementQuery.cs Replace 32+ occurrences of keyword matching with StartsWith calls
Utils.cs (DirectoryServices) Simplify character comparison and use AsSpan().StartsWith() for property name matching
EventLog.cs Replace substring comparison with AsSpan().Equals() for event source validation
OdbcUtils.cs Use AsSpan().StartsWith() for SQL token matching
DataTable.cs Replace suffix comparisons with EndsWith for " ASC" and " DESC" detection
UrlPath.cs Use AsSpan().Equals() for case-insensitive path comparison
StringUtil.cs Add null checks and use StartsWith for both ordinal and ignore-case variants
AppSettingsReader.cs Use AsSpan().Equals() for substring comparison in null string detection
ReflectPropertyDescriptor.cs Replace case-insensitive Compare with Equals for property name matching
DesignerOptionService.cs Replace case-insensitive Compare with Equals for child collection lookup
ComponentResourceManager.cs Simplify if/else logic to single StartsWith with conditional StringComparison
CredentialCacheKey.cs Use AsSpan().Equals() for URI prefix path comparison
Program.cs (dotnet-pgo) Replace file extension comparisons with string.Equals
AssemblyQualifiedToken.cs Use direct string equality operator instead of CompareOrdinal
EcmaModule.Sorting.cs Use StringComparer.Equals in assertion instead of Compare != 0

@Rob-Hague
Copy link
Contributor

An outsider might imagine that AI would be put to better use by improving CA2251, if these cases are not already caught by it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants

Comments